pax_global_header00006660000000000000000000000064151714323230014513gustar00rootroot0000000000000052 comment=9e9a11132c980c4ec84ff6d2df06d4c1a55ca8f3 pydantic-pydantic-ba0aa01/000077500000000000000000000000001517143232300156065ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/.git-blame-ignore-revs000066400000000000000000000007121517143232300217060ustar00rootroot00000000000000# Linting/formatting: # isort/pyupgrade -> Ruff: 4f3e794a69e84e4294c605c669e4d1876a18dd50 # Black -> Ruff format: 419398d1dd9f3c0babdcfde1d52c249266f59ef0 # Ruff 0.2.1: 918402f01d82694214ff93cd77ff62d5d5beb1ab # Ruff 0.4.8: 332e77ba3b658c2a57fc72f832587b72311d87c7 # Replace `py` -> `python` in code blocks: 33c4812cb3b7160d663620f84dd17eeda1480539 # Markdownlint: c4f0262bd64734751a68846a10edd6cdc6acc6f6 # yamlfmt: 19223b9ce61537995cbc4c46141148ac619a60af pydantic-pydantic-ba0aa01/.github/000077500000000000000000000000001517143232300171465ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/.github/FUNDING.yml000066400000000000000000000000251517143232300207600ustar00rootroot00000000000000github: samuelcolvin pydantic-pydantic-ba0aa01/.github/ISSUE_TEMPLATE/000077500000000000000000000000001517143232300213315ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/.github/ISSUE_TEMPLATE/bug-v1.yml000066400000000000000000000073501517143232300231620ustar00rootroot00000000000000name: 🐛 Pydantic V1.X Bug description: Report a bug or unexpected behavior in Pydantic V1.X, e.g. all releases prior to V2 labels: [bug V1, pending] body: - type: markdown attributes: value: Thank you for contributing to pydantic! ✊ - type: checkboxes id: checks attributes: label: Initial Checks description: | Just a few checks to make sure you need to create a bug report. _Sorry to sound so draconian 👿; but every second spent replying to issues is time not spent improving pydantic 🙇._ options: - label: I have searched GitHub for a duplicate issue and I'm sure this is something new required: true - label: I have searched Google & StackOverflow for a solution and couldn't find anything required: true - label: I have read and followed [the docs](https://docs.pydantic.dev) and still think this is a bug required: true - label: > I am confident that the issue is with pydantic (not my code, or another library in the ecosystem like [FastAPI](https://fastapi.tiangolo.com) or [mypy](https://mypy.readthedocs.io/en/stable)) required: true - type: textarea id: description attributes: label: Description description: | Please explain what you're seeing and what you would expect to see. Please provide as much detail as possible to make understanding and solving your problem as quick as possible. 🙏 validations: required: true - type: textarea id: example attributes: label: Example Code description: > If applicable, please add a self-contained, [minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example) demonstrating the bug. placeholder: | import pydantic ... render: Python - type: textarea id: version attributes: label: Python, Pydantic & OS Version description: | Which version of Python & Pydantic are you using, and which Operating System? Please run the following command and copy the output below: ```bash python -c "import pydantic.utils; print(pydantic.utils.version_info())" ``` render: Text validations: required: true - type: checkboxes id: affected-components attributes: label: Affected Components description: Which of the following parts of pydantic does this bug affect? # keep this lis in sync with feature_request.yml options: - label: '[Compatibility between releases](https://docs.pydantic.dev/changelog/)' - label: '[Data validation/parsing](https://docs.pydantic.dev/concepts/models/#basic-model-usage)' - label: '[Data serialization](https://docs.pydantic.dev/concepts/serialization/) - `.model_dump()` and `.model_dump_json()`' - label: '[JSON Schema](https://docs.pydantic.dev/concepts/json_schema/)' - label: '[Dataclasses](https://docs.pydantic.dev/concepts/dataclasses/)' - label: '[Model Config](https://docs.pydantic.dev/concepts/config/)' - label: '[Field Types](https://docs.pydantic.dev/api/types/) - adding or changing a particular data type' - label: '[Function validation decorator](https://docs.pydantic.dev/concepts/validation_decorator/)' - label: '[Generic Models](https://docs.pydantic.dev/concepts/models/#generic-models)' - label: '[Other Model behaviour](https://docs.pydantic.dev/concepts/models/) - `model_construct()`, pickling, private attributes, ORM mode' - label: '[Plugins](https://docs.pydantic.dev/) and integration with other tools - mypy, FastAPI, python-devtools, Hypothesis, VS Code, PyCharm, etc.' pydantic-pydantic-ba0aa01/.github/ISSUE_TEMPLATE/bug-v2.yml000066400000000000000000000031061517143232300231560ustar00rootroot00000000000000name: 🐛 Pydantic V2 Bug description: Report a bug or unexpected behavior in Pydantic V2 labels: [bug V2, pending] body: - type: markdown attributes: value: Thank you for contributing to pydantic! ✊ - type: checkboxes id: checks attributes: label: Initial Checks description: Just making sure you're really using Pydantic V2 options: - label: I confirm that I'm using Pydantic V2 required: true - type: textarea id: description attributes: label: Description description: | Please explain what you're seeing and what you would expect to see. Please provide as much detail as possible to make understanding and solving your problem as quick as possible. 🙏 validations: required: true - type: textarea id: example attributes: label: Example Code description: > If applicable, please add a self-contained, [minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example) demonstrating the bug. placeholder: | import pydantic ... render: Python - type: textarea id: version attributes: label: Python, Pydantic & OS Version description: | Which version of Python & Pydantic are you using, and which Operating System? Please run the following command and copy the output below: ```bash python -c "import pydantic.version; print(pydantic.version.version_info())" ``` render: Text validations: required: true pydantic-pydantic-ba0aa01/.github/ISSUE_TEMPLATE/config.yml000066400000000000000000000003471517143232300233250ustar00rootroot00000000000000blank_issues_enabled: true contact_links: - name: 🤔 Ask a Question url: 'https://github.com/pydantic/pydantic/discussions/new?category=question' about: Ask a question about how to use pydantic using github discussions pydantic-pydantic-ba0aa01/.github/ISSUE_TEMPLATE/feature_request.yml000066400000000000000000000053701517143232300252640ustar00rootroot00000000000000name: 🚀 Pydantic V2 Feature request description: 'Suggest a new feature for Pydantic V2 (NOTE: and we only making critical bug fixes to Pydantic V1)' labels: [feature request] body: - type: markdown attributes: value: Thank you for contributing to pydantic! ✊ - type: checkboxes id: searched attributes: label: Initial Checks description: | Just a few checks to make sure you need to create a feature request. _Sorry to sound so draconian 👿; but every second spent replying to issues is time not spent improving pydantic 🙇._ options: - label: I have searched Google & GitHub for similar requests and couldn't find anything required: true - label: I have read and followed [the docs](https://docs.pydantic.dev) and still think this feature is missing required: true - type: textarea id: description attributes: label: Description description: | Please give as much detail as possible about the feature you would like to suggest. 🙏 You might like to add: * A demo of how code might look when using the feature * Your use case(s) for the feature * Why the feature should be added to pydantic (as opposed to another library or just implemented in your code) validations: required: true - type: checkboxes id: affected-components attributes: label: Affected Components description: Which of the following parts of pydantic does this feature affect? # keep this lis in sync with bug.yml options: - label: '[Compatibility between releases](https://docs.pydantic.dev/changelog/)' - label: '[Data validation/parsing](https://docs.pydantic.dev/concepts/models/#basic-model-usage)' - label: '[Data serialization](https://docs.pydantic.dev/concepts/serialization/) - `.model_dump()` and `.model_dump_json()`' - label: '[JSON Schema](https://docs.pydantic.dev/concepts/json_schema/)' - label: '[Dataclasses](https://docs.pydantic.dev/concepts/dataclasses/)' - label: '[Model Config](https://docs.pydantic.dev/concepts/config/)' - label: '[Field Types](https://docs.pydantic.dev/api/types/) - adding or changing a particular data type' - label: '[Function validation decorator](https://docs.pydantic.dev/concepts/validation_decorator/)' - label: '[Generic Models](https://docs.pydantic.dev/concepts/models/#generic-models)' - label: '[Other Model behaviour](https://docs.pydantic.dev/concepts/models/) - `model_construct()`, pickling, private attributes, ORM mode' - label: '[Plugins](https://docs.pydantic.dev/) and integration with other tools - mypy, FastAPI, python-devtools, Hypothesis, VS Code, PyCharm, etc.' pydantic-pydantic-ba0aa01/.github/PULL_REQUEST_TEMPLATE.md000066400000000000000000000012711517143232300227500ustar00rootroot00000000000000 ## Change Summary ## Related issue number ## Checklist * [ ] The pull request title is a good summary of the changes - it will be used in the changelog * [ ] Unit tests for the changes exist * [ ] Tests pass on CI * [ ] Documentation reflects the changes where applicable * [ ] My PR is ready to review, **please add a comment including the phrase "please review" to assign reviewers** pydantic-pydantic-ba0aa01/.github/actions/000077500000000000000000000000001517143232300206065ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/.github/actions/core-build-pgo-wheel/000077500000000000000000000000001517143232300245205ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/.github/actions/core-build-pgo-wheel/action.yml000066400000000000000000000062131517143232300265220ustar00rootroot00000000000000name: Build PGO wheel description: Builds a PGO-optimized wheel inputs: interpreter: description: 'Interpreter to build the wheel for' required: true rust-toolchain: description: 'Rust toolchain to use' required: true working-directory: description: 'Working directory to run the action in' required: false default: ${{ github.workspace }} outputs: wheel: description: 'Path to the built wheel' value: ${{ steps.find_wheel.outputs.path }} runs: using: composite steps: - name: Prepare profiling directory shell: bash # making this ahead of the compile ensures that the local user can write to this # directory; the maturin action (on linux) runs in docker so would create as root run: mkdir -p ${{ github.workspace }}/profdata - name: Build initial wheel uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad # v1.50.1 with: working-directory: ${{ inputs.working-directory }} manylinux: auto args: > --release --out initial-wheel --interpreter ${{ inputs.interpreter }} rust-toolchain: ${{ inputs.rust-toolchain }} docker-options: -e CI env: RUSTFLAGS: '-Cprofile-generate=${{ github.workspace }}/profdata' - name: Generate pgo data # Until we move all dev dependencies to the main `pydantic` package, use this workaround: # Sync the pydantic-core workspace to get the dev dependencies (without the actual `pydantic-core` package), # and then sync the parent workspace: run: | export RUST_HOST=$(rustc --print host-tuple) uv sync --directory pydantic-core --group testing-extra --no-install-package pydantic-core uv sync --group testing-extra --no-install-package pydantic-core --inexact uv pip install pydantic-core --no-index --no-deps --find-links pydantic-core/initial-wheel uv run --no-sync pytest tests/pydantic_core/benchmarks rustup run ${INPUTS_RUST_TOOLCHAIN} bash -c 'echo LLVM_PROFDATA=$RUSTUP_HOME/toolchains/$RUSTUP_TOOLCHAIN/lib/rustlib/$RUST_HOST/bin/llvm-profdata >> "$GITHUB_ENV"' shell: bash env: INPUTS_RUST_TOOLCHAIN: ${{ inputs.rust-toolchain }} - name: Merge pgo data run: ${{ env.LLVM_PROFDATA }} merge -o ${{ github.workspace }}/merged.profdata ${{ github.workspace }}/profdata # zizmor: ignore[template-injection] shell: pwsh # because it handles paths on windows better, and works well enough on unix for this step - name: Build pgo-optimized wheel uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad # v1.50.1 with: working-directory: ${{ inputs.working-directory }} manylinux: auto args: > --release --out dist --interpreter ${{ inputs.interpreter }} rust-toolchain: ${{inputs.rust-toolchain}} docker-options: -e CI env: RUSTFLAGS: '-Cprofile-use=${{ github.workspace }}/merged.profdata' - name: Find built wheel id: find_wheel working-directory: pydantic-core run: echo "path=$(ls dist/*.whl)" | tee -a "$GITHUB_OUTPUT" shell: bash pydantic-pydantic-ba0aa01/.github/actions/people/000077500000000000000000000000001517143232300220725ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/.github/actions/people/action.yml000066400000000000000000000015211517143232300240710ustar00rootroot00000000000000name: Update Pydantic people description: Update Pydantic contributors in documentation inputs: token: description: 'User token for accessing the GitHub API. Can be passed in using {{ secrets.GITHUB_TOKEN }}' required: true runs: using: composite steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: true - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: python-version: '3.14' activate-environment: true - name: Install dependencies run: uv pip install --requirements .github/actions/people/pylock.toml shell: bash - name: Update pydantic people run: uv run --no-sync .github/actions/people/people.py shell: bash env: INPUT_TOKEN: ${{ inputs.token }} pydantic-pydantic-ba0aa01/.github/actions/people/people.py000066400000000000000000000530071517143232300237350ustar00rootroot00000000000000"""Use the github API to get lists of people who have contributed in various ways to Pydantic. This logic is inspired by that of @tiangolo's [FastAPI people script](https://github.com/tiangolo/fastapi/blob/master/.github/actions/people/app/main.py). """ # ruff: noqa: D101 # ruff: noqa: D103 import logging import subprocess import sys from collections import Counter from collections.abc import Container from datetime import datetime, timedelta, timezone from pathlib import Path from typing import Any import requests import yaml from github import Github from pydantic_settings import BaseSettings from pydantic import BaseModel, SecretStr github_graphql_url = 'https://api.github.com/graphql' discussions_query = """ query Q($after: String) { repository(name: "pydantic", owner: "pydantic") { discussions(first: 100, after: $after) { edges { cursor node { number author { login avatarUrl url } title createdAt comments(first: 100) { nodes { createdAt author { login avatarUrl url } isAnswer replies(first: 10) { nodes { createdAt author { login avatarUrl url } } } } } } } } } } """ issues_query = """ query Q($after: String) { repository(name: "pydantic", owner: "pydantic") { issues(first: 100, after: $after) { edges { cursor node { number author { login avatarUrl url } title createdAt state comments(first: 100) { nodes { createdAt author { login avatarUrl url } } } } } } } } """ prs_query = """ query Q($after: String) { repository(name: "pydantic", owner: "pydantic") { pullRequests(first: 100, after: $after) { edges { cursor node { number labels(first: 100) { nodes { name } } author { login avatarUrl url } title createdAt state comments(first: 100) { nodes { createdAt author { login avatarUrl url } } } reviews(first:100) { nodes { author { login avatarUrl url } state } } } } } } } """ class Author(BaseModel): """Represents a GitHub user with their basic information.""" login: str avatarUrl: str url: str # Issues and Discussions class CommentsNode(BaseModel): """Represents a comment node with creation time and author information.""" createdAt: datetime author: Author | None = None class Replies(BaseModel): """Container for reply nodes in a discussion.""" nodes: list[CommentsNode] class DiscussionsCommentsNode(CommentsNode): """Extends CommentsNode to include replies in discussions.""" replies: Replies class Comments(BaseModel): """Container for comment nodes.""" nodes: list[CommentsNode] class DiscussionsComments(BaseModel): """Container for discussion comment nodes.""" nodes: list[DiscussionsCommentsNode] class IssuesNode(BaseModel): """Represents a GitHub issue with its metadata and comments.""" number: int author: Author | None = None title: str createdAt: datetime state: str comments: Comments class DiscussionsNode(BaseModel): """Represents a GitHub discussion with its metadata and comments.""" number: int author: Author | None = None title: str createdAt: datetime comments: DiscussionsComments class IssuesEdge(BaseModel): """Represents an edge in the GitHub GraphQL issues query.""" cursor: str node: IssuesNode class DiscussionsEdge(BaseModel): """Represents an edge in the GitHub GraphQL discussions query.""" cursor: str node: DiscussionsNode class Issues(BaseModel): """Container for issue edges.""" edges: list[IssuesEdge] class Discussions(BaseModel): """Container for discussion edges.""" edges: list[DiscussionsEdge] class IssuesRepository(BaseModel): """Represents a repository's issues in the GitHub GraphQL response.""" issues: Issues class DiscussionsRepository(BaseModel): """Represents a repository's discussions in the GitHub GraphQL response.""" discussions: Discussions class IssuesResponseData(BaseModel): """Top-level container for issues response data.""" repository: IssuesRepository class DiscussionsResponseData(BaseModel): """Top-level container for discussions response data.""" repository: DiscussionsRepository class IssuesResponse(BaseModel): """Complete response structure for issues query.""" data: IssuesResponseData class DiscussionsResponse(BaseModel): """Complete response structure for discussions query.""" data: DiscussionsResponseData # PRs class LabelNode(BaseModel): """Represents a GitHub label.""" name: str class Labels(BaseModel): """Container for label nodes.""" nodes: list[LabelNode] class ReviewNode(BaseModel): """Represents a pull request review with author and state.""" author: Author | None = None state: str class Reviews(BaseModel): """Container for review nodes.""" nodes: list[ReviewNode] class PullRequestNode(BaseModel): """Represents a GitHub pull request with its metadata and interactions.""" number: int labels: Labels author: Author | None = None title: str createdAt: datetime state: str comments: Comments reviews: Reviews class PullRequestEdge(BaseModel): """Represents an edge in the GitHub GraphQL pull requests query.""" cursor: str node: PullRequestNode class PullRequests(BaseModel): """Container for pull request edges.""" edges: list[PullRequestEdge] class PRsRepository(BaseModel): """Represents a repository's pull requests in the GitHub GraphQL response.""" pullRequests: PullRequests class PRsResponseData(BaseModel): """Top-level container for pull requests response data.""" repository: PRsRepository class PRsResponse(BaseModel): """Complete response structure for pull requests query.""" data: PRsResponseData class Settings(BaseSettings): """Configuration settings for the GitHub API interaction.""" input_token: SecretStr github_repository: str = 'pydantic/pydantic' request_timeout: int = 30 def get_graphql_response( *, settings: Settings, query: str, after: str | None = None, ) -> dict[str, Any]: """Make a GraphQL request to GitHub API. Args: settings: Configuration settings including API token query: GraphQL query string after: Cursor for pagination, if any Returns: Response data from GitHub API in JSON format Raises: RuntimeError: If the API request fails or returns errors """ headers = {'Authorization': f'token {settings.input_token.get_secret_value()}'} variables = {'after': after} response = requests.post( github_graphql_url, headers=headers, timeout=settings.request_timeout, json={'query': query, 'variables': variables, 'operationName': 'Q'}, ) if response.status_code != 200: logging.error(f'Response was not 200, after: {after}') logging.error(response.text) raise RuntimeError(response.text) data = response.json() if 'errors' in data: logging.error(f'Errors in response, after: {after}') logging.error(data['errors']) logging.error(response.text) raise RuntimeError(response.text) return data def get_graphql_issue_edges(*, settings: Settings, after: str | None = None) -> list[IssuesEdge]: """Fetch issue edges from GitHub GraphQL API. Args: settings: Configuration settings after: Cursor for pagination, if any Returns: List of issue edges from the GraphQL response """ data = get_graphql_response(settings=settings, query=issues_query, after=after) graphql_response = IssuesResponse.model_validate(data) return graphql_response.data.repository.issues.edges def get_graphql_question_discussion_edges( *, settings: Settings, after: str | None = None, ) -> list[DiscussionsEdge]: """Fetch discussion edges from GitHub GraphQL API. Args: settings: Configuration settings after: Cursor for pagination, if any Returns: List of discussion edges from the GraphQL response """ data = get_graphql_response( settings=settings, query=discussions_query, after=after, ) graphql_response = DiscussionsResponse.model_validate(data) return graphql_response.data.repository.discussions.edges def get_graphql_pr_edges(*, settings: Settings, after: str | None = None) -> list[PullRequestEdge]: """Fetch pull request edges from GitHub GraphQL API. Args: settings: Configuration settings after: Cursor for pagination, if any Returns: List of pull request edges from the GraphQL response """ data = get_graphql_response(settings=settings, query=prs_query, after=after) graphql_response = PRsResponse.model_validate(data) return graphql_response.data.repository.pullRequests.edges def get_issues_experts(settings: Settings) -> tuple[Counter, Counter, dict[str, Author]]: """Analyze issues to identify expert contributors. Args: settings: Configuration settings Returns: A tuple containing: - Counter of all commentors - Counter of commentors from the last month - Dictionary mapping usernames to Author objects """ issue_nodes: list[IssuesNode] = [] issue_edges = get_graphql_issue_edges(settings=settings) while issue_edges: issue_nodes.extend(edge.node for edge in issue_edges) last_edge = issue_edges[-1] issue_edges = get_graphql_issue_edges(settings=settings, after=last_edge.cursor) commentors = Counter() last_month_commentors = Counter() authors: dict[str, Author] = {} now = datetime.now(tz=timezone.utc) one_month_ago = now - timedelta(days=30) for issue in issue_nodes: issue_author_name = None if issue.author: authors[issue.author.login] = issue.author issue_author_name = issue.author.login issue_commentors = set() for comment in issue.comments.nodes: if comment.author: authors[comment.author.login] = comment.author if comment.author.login != issue_author_name: issue_commentors.add(comment.author.login) for author_name in issue_commentors: commentors[author_name] += 1 if issue.createdAt > one_month_ago: last_month_commentors[author_name] += 1 return commentors, last_month_commentors, authors def get_discussions_experts(settings: Settings) -> tuple[Counter, Counter, dict[str, Author]]: """Analyze discussions to identify expert contributors. Args: settings: Configuration settings Returns: A tuple containing: - Counter of all commentors - Counter of commentors from the last month - Dictionary mapping usernames to Author objects """ discussion_nodes: list[DiscussionsNode] = [] discussion_edges = get_graphql_question_discussion_edges(settings=settings) while discussion_edges: discussion_nodes.extend(discussion_edge.node for discussion_edge in discussion_edges) last_edge = discussion_edges[-1] discussion_edges = get_graphql_question_discussion_edges(settings=settings, after=last_edge.cursor) commentors = Counter() last_month_commentors = Counter() authors: dict[str, Author] = {} now = datetime.now(tz=timezone.utc) one_month_ago = now - timedelta(days=30) for discussion in discussion_nodes: discussion_author_name = None if discussion.author: authors[discussion.author.login] = discussion.author discussion_author_name = discussion.author.login discussion_commentors = set() for comment in discussion.comments.nodes: if comment.author: authors[comment.author.login] = comment.author if comment.author.login != discussion_author_name: discussion_commentors.add(comment.author.login) for reply in comment.replies.nodes: if reply.author: authors[reply.author.login] = reply.author if reply.author.login != discussion_author_name: discussion_commentors.add(reply.author.login) for author_name in discussion_commentors: commentors[author_name] += 1 if discussion.createdAt > one_month_ago: last_month_commentors[author_name] += 1 return commentors, last_month_commentors, authors def get_experts(settings: Settings) -> tuple[Counter, Counter, dict[str, Author]]: """Get combined expert contributors from discussions. Args: settings: Configuration settings Returns: A tuple containing: - Counter of all commentors - Counter of commentors from the last month - Dictionary mapping usernames to Author objects """ # Migrated to only use GitHub Discussions # ( # issues_commentors, # issues_last_month_commentors, # issues_authors, # ) = get_issues_experts(settings=settings) ( discussions_commentors, discussions_last_month_commentors, discussions_authors, ) = get_discussions_experts(settings=settings) # commentors = issues_commentors + discussions_commentors commentors = discussions_commentors # last_month_commentors = ( # issues_last_month_commentors + discussions_last_month_commentors # ) last_month_commentors = discussions_last_month_commentors # authors = {**issues_authors, **discussions_authors} authors = {**discussions_authors} return commentors, last_month_commentors, authors def get_contributors(settings: Settings) -> tuple[Counter, Counter, Counter, dict[str, Author]]: """Analyze pull requests to identify contributors, commentors, and reviewers. Args: settings: Configuration settings Returns: A tuple containing: - Counter of contributors (merged PRs) - Counter of commentors - Counter of reviewers - Dictionary mapping usernames to Author objects """ pr_nodes: list[PullRequestNode] = [] pr_edges = get_graphql_pr_edges(settings=settings) while pr_edges: pr_nodes.extend(edge.node for edge in pr_edges) last_edge = pr_edges[-1] pr_edges = get_graphql_pr_edges(settings=settings, after=last_edge.cursor) contributors = Counter() commentors = Counter() reviewers = Counter() authors: dict[str, Author] = {} for pr in pr_nodes: author_name = None if pr.author: authors[pr.author.login] = pr.author author_name = pr.author.login pr_commentors: set[str] = set() pr_reviewers: set[str] = set() for comment in pr.comments.nodes: if comment.author: authors[comment.author.login] = comment.author if comment.author.login == author_name: continue pr_commentors.add(comment.author.login) for author_name in pr_commentors: commentors[author_name] += 1 for review in pr.reviews.nodes: if review.author: authors[review.author.login] = review.author pr_reviewers.add(review.author.login) for reviewer in pr_reviewers: reviewers[reviewer] += 1 if pr.state == 'MERGED' and pr.author: contributors[pr.author.login] += 1 return contributors, commentors, reviewers, authors def get_top_users( *, counter: Counter, min_count: int, authors: dict[str, Author], skip_users: Container[str], ) -> list[dict[str, Any]]: """Get top users based on their contribution counts. Args: counter: Counter with user contribution counts min_count: Minimum count to be included in results authors: Dictionary mapping usernames to Author objects skip_users: Container of usernames to exclude from results Returns: List of dictionaries containing: - login: Username - count: Number of contributions - avatarUrl: URL to user's avatar - url: URL to user's GitHub profile """ users: list[dict[str, Any]] = [] for commentor, count in counter.most_common(50): if commentor in skip_users: continue if count >= min_count: author = authors[commentor] users.append( { 'login': commentor, 'count': count, 'avatarUrl': author.avatarUrl, 'url': author.url, } ) return users if __name__ == '__main__': logging.basicConfig(level=logging.INFO) settings = Settings() logging.info(f'Using config: {settings.model_dump_json()}') g = Github(settings.input_token.get_secret_value()) repo = g.get_repo(settings.github_repository) question_commentors, question_last_month_commentors, question_authors = get_experts(settings=settings) contributors, pr_commentors, reviewers, pr_authors = get_contributors(settings=settings) authors = {**question_authors, **pr_authors} maintainers_logins = { 'samuelcolvin', 'adriangb', 'dmontagu', 'hramezani', 'Kludex', 'davidhewitt', 'alexmojaki', 'Viicos', } bot_names = {'codecov', 'github-actions', 'pre-commit-ci', 'dependabot', 'dependabot-preview'} maintainers = [] for login in maintainers_logins: user = authors[login] maintainers.append( { 'login': login, 'answers': question_commentors[login], 'prs': contributors[login], 'avatarUrl': user.avatarUrl, 'url': user.url, } ) min_count_expert = 10 min_count_last_month = 3 min_count_contributor = 4 min_count_reviewer = 4 experts = get_top_users( counter=question_commentors, min_count=min_count_expert, authors=authors, skip_users=bot_names, ) last_month_active = get_top_users( counter=question_last_month_commentors, min_count=min_count_last_month, authors=authors, skip_users=bot_names, ) top_contributors = get_top_users( counter=contributors, min_count=min_count_contributor, authors=authors, skip_users=bot_names, ) top_reviewers = get_top_users( counter=reviewers, min_count=min_count_reviewer, authors=authors, skip_users=bot_names, ) extra_experts = [ { 'login': 'ybressler', 'count': 3, 'avatarUrl': 'https://avatars.githubusercontent.com/u/40807730?v=4', 'url': 'https://github.com/ybressler', }, ] expert_logins = {e['login'] for e in experts} experts.extend([expert for expert in extra_experts if expert['login'] not in expert_logins]) people = { 'maintainers': maintainers, 'experts': experts, 'last_month_active': last_month_active, 'top_contributors': top_contributors, 'top_reviewers': top_reviewers, } people_path = Path('./docs/plugins/people.yml') people_old_content = people_path.read_text(encoding='utf-8') new_people_content = yaml.dump(people, sort_keys=False, width=200, allow_unicode=True) if people_old_content == new_people_content: logging.info("The Pydantic People data hasn't changed, finishing.") sys.exit(0) people_path.write_text(new_people_content, encoding='utf-8') logging.info('Setting up GitHub Actions git user') subprocess.run(['git', 'config', 'user.name', 'github-actions'], check=True) subprocess.run(['git', 'config', 'user.email', 'github-actions@github.com'], check=True) branch_name = 'pydantic-people-update' logging.info(f'Creating a new branch {branch_name}') subprocess.run(['git', 'checkout', '-b', branch_name], check=True) logging.info('Adding updated file') subprocess.run(['git', 'add', str(people_path)], check=True) logging.info('Committing updated file') message = '👥 Update Pydantic People' result = subprocess.run(['git', 'commit', '-m', message], check=True) logging.info('Pushing branch') subprocess.run(['git', 'push', 'origin', branch_name], check=True) logging.info('Creating PR') pr = repo.create_pull(title=message, body=message, base='main', head=branch_name) logging.info(f'Created PR: {pr.number}') logging.info('Finished') pydantic-pydantic-ba0aa01/.github/actions/people/pylock.toml000066400000000000000000002415141517143232300242770ustar00rootroot00000000000000# This file was autogenerated by uv via the following command: # uv pip compile --universal --format pylock.toml requirements.in --output-file pylock.toml lock-version = "1.0" created-by = "uv" requires-python = ">=3.13" [[packages]] name = "annotated-types" version = "0.7.0" sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", upload-time = 2024-05-20T21:33:25Z, size = 16081, hashes = { sha256 = "aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89" } } wheels = [{ url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", upload-time = 2024-05-20T21:33:24Z, size = 13643, hashes = { sha256 = "1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53" } }] [[packages]] name = "certifi" version = "2026.2.25" sdist = { url = "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz", upload-time = 2026-02-25T02:54:17Z, size = 155029, hashes = { sha256 = "e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7" } } wheels = [{ url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", upload-time = 2026-02-25T02:54:15Z, size = 153684, hashes = { sha256 = "027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa" } }] [[packages]] name = "cffi" version = "2.0.0" marker = "python_full_version >= '3.9' and platform_python_implementation != 'PyPy'" sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", upload-time = 2025-09-08T23:24:04Z, size = 523588, hashes = { sha256 = "44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529" } } wheels = [ { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", upload-time = 2025-09-08T23:23:00Z, size = 185230, hashes = { sha256 = "00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb" } }, { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", upload-time = 2025-09-08T23:23:02Z, size = 181043, hashes = { sha256 = "45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca" } }, { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", upload-time = 2025-09-08T23:23:03Z, size = 212446, hashes = { sha256 = "07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b" } }, { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", upload-time = 2025-09-08T23:23:04Z, size = 220101, hashes = { sha256 = "d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b" } }, { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", upload-time = 2025-09-08T23:23:06Z, size = 207948, hashes = { sha256 = "f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2" } }, { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", upload-time = 2025-09-08T23:23:07Z, size = 206422, hashes = { sha256 = "dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3" } }, { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", upload-time = 2025-09-08T23:23:09Z, size = 219499, hashes = { sha256 = "c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26" } }, { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", upload-time = 2025-09-08T23:23:10Z, size = 222928, hashes = { sha256 = "d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c" } }, { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", upload-time = 2025-09-08T23:23:12Z, size = 221302, hashes = { sha256 = "6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b" } }, { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", upload-time = 2025-09-08T23:23:14Z, size = 172909, hashes = { sha256 = "74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27" } }, { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", upload-time = 2025-09-08T23:23:15Z, size = 183402, hashes = { sha256 = "19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75" } }, { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", upload-time = 2025-09-08T23:23:16Z, size = 177780, hashes = { sha256 = "256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91" } }, { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", upload-time = 2025-09-08T23:23:18Z, size = 185320, hashes = { sha256 = "fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5" } }, { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", upload-time = 2025-09-08T23:23:19Z, size = 181487, hashes = { sha256 = "c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13" } }, { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", upload-time = 2025-09-08T23:23:20Z, size = 220049, hashes = { sha256 = "24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b" } }, { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", upload-time = 2025-09-08T23:23:22Z, size = 207793, hashes = { sha256 = "12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c" } }, { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", upload-time = 2025-09-08T23:23:23Z, size = 206300, hashes = { sha256 = "d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef" } }, { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", upload-time = 2025-09-08T23:23:24Z, size = 219244, hashes = { sha256 = "afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775" } }, { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", upload-time = 2025-09-08T23:23:26Z, size = 222828, hashes = { sha256 = "737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205" } }, { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", upload-time = 2025-09-08T23:23:27Z, size = 220926, hashes = { sha256 = "38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1" } }, { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", upload-time = 2025-09-08T23:23:44Z, size = 175328, hashes = { sha256 = "087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f" } }, { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", upload-time = 2025-09-08T23:23:45Z, size = 185650, hashes = { sha256 = "203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25" } }, { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", upload-time = 2025-09-08T23:23:47Z, size = 180687, hashes = { sha256 = "dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad" } }, { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", upload-time = 2025-09-08T23:23:29Z, size = 188773, hashes = { sha256 = "9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9" } }, { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", upload-time = 2025-09-08T23:23:30Z, size = 185013, hashes = { sha256 = "7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d" } }, { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", upload-time = 2025-09-08T23:23:31Z, size = 221593, hashes = { sha256 = "7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c" } }, { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", upload-time = 2025-09-08T23:23:33Z, size = 209354, hashes = { sha256 = "92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8" } }, { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", upload-time = 2025-09-08T23:23:34Z, size = 208480, hashes = { sha256 = "b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc" } }, { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", upload-time = 2025-09-08T23:23:36Z, size = 221584, hashes = { sha256 = "28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592" } }, { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", upload-time = 2025-09-08T23:23:37Z, size = 224443, hashes = { sha256 = "7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512" } }, { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", upload-time = 2025-09-08T23:23:38Z, size = 223437, hashes = { sha256 = "6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4" } }, { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", upload-time = 2025-09-08T23:23:40Z, size = 180487, hashes = { sha256 = "1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e" } }, { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", upload-time = 2025-09-08T23:23:41Z, size = 191726, hashes = { sha256 = "d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6" } }, { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", upload-time = 2025-09-08T23:23:43Z, size = 184195, hashes = { sha256 = "0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9" } }, ] [[packages]] name = "charset-normalizer" version = "3.4.7" sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", upload-time = 2026-04-02T09:28:39Z, size = 144271, hashes = { sha256 = "ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5" } } wheels = [ { url = "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl", upload-time = 2026-04-02T09:26:45Z, size = 309627, hashes = { sha256 = "f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063" } }, { url = "https://files.pythonhosted.org/packages/2e/4e/b7f84e617b4854ade48a1b7915c8ccfadeba444d2a18c291f696e37f0d3b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", upload-time = 2026-04-02T09:26:46Z, size = 207008, hashes = { sha256 = "0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c" } }, { url = "https://files.pythonhosted.org/packages/c4/bb/ec73c0257c9e11b268f018f068f5d00aa0ef8c8b09f7753ebd5f2880e248/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", upload-time = 2026-04-02T09:26:48Z, size = 228303, hashes = { sha256 = "a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66" } }, { url = "https://files.pythonhosted.org/packages/85/fb/32d1f5033484494619f701e719429c69b766bfc4dbc61aa9e9c8c166528b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", upload-time = 2026-04-02T09:26:49Z, size = 224282, hashes = { sha256 = "3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18" } }, { url = "https://files.pythonhosted.org/packages/fa/07/330e3a0dda4c404d6da83b327270906e9654a24f6c546dc886a0eb0ffb23/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", upload-time = 2026-04-02T09:26:50Z, size = 215595, hashes = { sha256 = "e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd" } }, { url = "https://files.pythonhosted.org/packages/e3/7c/fc890655786e423f02556e0216d4b8c6bcb6bdfa890160dc66bf52dee468/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_armv7l.whl", upload-time = 2026-04-02T09:26:52Z, size = 201986, hashes = { sha256 = "f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215" } }, { url = "https://files.pythonhosted.org/packages/d8/97/bfb18b3db2aed3b90cf54dc292ad79fdd5ad65c4eae454099475cbeadd0d/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", upload-time = 2026-04-02T09:26:53Z, size = 211711, hashes = { sha256 = "e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859" } }, { url = "https://files.pythonhosted.org/packages/6f/a5/a581c13798546a7fd557c82614a5c65a13df2157e9ad6373166d2a3e645d/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", upload-time = 2026-04-02T09:26:54Z, size = 210036, hashes = { sha256 = "7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8" } }, { url = "https://files.pythonhosted.org/packages/8c/bf/b3ab5bcb478e4193d517644b0fb2bf5497fbceeaa7a1bc0f4d5b50953861/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_armv7l.whl", upload-time = 2026-04-02T09:26:56Z, size = 202998, hashes = { sha256 = "481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5" } }, { url = "https://files.pythonhosted.org/packages/e7/4e/23efd79b65d314fa320ec6017b4b5834d5c12a58ba4610aa353af2e2f577/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", upload-time = 2026-04-02T09:26:57Z, size = 230056, hashes = { sha256 = "f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832" } }, { url = "https://files.pythonhosted.org/packages/b9/9f/1e1941bc3f0e01df116e68dc37a55c4d249df5e6fa77f008841aef68264f/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_riscv64.whl", upload-time = 2026-04-02T09:26:58Z, size = 211537, hashes = { sha256 = "f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6" } }, { url = "https://files.pythonhosted.org/packages/80/0f/088cbb3020d44428964a6c97fe1edfb1b9550396bf6d278330281e8b709c/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_s390x.whl", upload-time = 2026-04-02T09:27:00Z, size = 226176, hashes = { sha256 = "3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48" } }, { url = "https://files.pythonhosted.org/packages/6a/9f/130394f9bbe06f4f63e22641d32fc9b202b7e251c9aef4db044324dac493/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", upload-time = 2026-04-02T09:27:02Z, size = 217723, hashes = { sha256 = "64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a" } }, { url = "https://files.pythonhosted.org/packages/73/55/c469897448a06e49f8fa03f6caae97074fde823f432a98f979cc42b90e69/charset_normalizer-3.4.7-cp313-cp313-win32.whl", upload-time = 2026-04-02T09:27:03Z, size = 148085, hashes = { sha256 = "4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e" } }, { url = "https://files.pythonhosted.org/packages/5d/78/1b74c5bbb3f99b77a1715c91b3e0b5bdb6fe302d95ace4f5b1bec37b0167/charset_normalizer-3.4.7-cp313-cp313-win_amd64.whl", upload-time = 2026-04-02T09:27:04Z, size = 158819, hashes = { sha256 = "3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110" } }, { url = "https://files.pythonhosted.org/packages/68/86/46bd42279d323deb8687c4a5a811fd548cb7d1de10cf6535d099877a9a9f/charset_normalizer-3.4.7-cp313-cp313-win_arm64.whl", upload-time = 2026-04-02T09:27:05Z, size = 147915, hashes = { sha256 = "80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b" } }, { url = "https://files.pythonhosted.org/packages/97/c8/c67cb8c70e19ef1960b97b22ed2a1567711de46c4ddf19799923adc836c2/charset_normalizer-3.4.7-cp314-cp314-macosx_10_15_universal2.whl", upload-time = 2026-04-02T09:27:07Z, size = 309234, hashes = { sha256 = "c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0" } }, { url = "https://files.pythonhosted.org/packages/99/85/c091fdee33f20de70d6c8b522743b6f831a2f1cd3ff86de4c6a827c48a76/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", upload-time = 2026-04-02T09:27:08Z, size = 208042, hashes = { sha256 = "1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a" } }, { url = "https://files.pythonhosted.org/packages/87/1c/ab2ce611b984d2fd5d86a5a8a19c1ae26acac6bad967da4967562c75114d/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", upload-time = 2026-04-02T09:27:09Z, size = 228706, hashes = { sha256 = "54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b" } }, { url = "https://files.pythonhosted.org/packages/a8/29/2b1d2cb00bf085f59d29eb773ce58ec2d325430f8c216804a0a5cd83cbca/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", upload-time = 2026-04-02T09:27:11Z, size = 224727, hashes = { sha256 = "715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41" } }, { url = "https://files.pythonhosted.org/packages/47/5c/032c2d5a07fe4d4855fea851209cca2b6f03ebeb6d4e3afdb3358386a684/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", upload-time = 2026-04-02T09:27:12Z, size = 215882, hashes = { sha256 = "bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e" } }, { url = "https://files.pythonhosted.org/packages/2c/c2/356065d5a8b78ed04499cae5f339f091946a6a74f91e03476c33f0ab7100/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_armv7l.whl", upload-time = 2026-04-02T09:27:13Z, size = 200860, hashes = { sha256 = "c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae" } }, { url = "https://files.pythonhosted.org/packages/0c/cd/a32a84217ced5039f53b29f460962abb2d4420def55afabe45b1c3c7483d/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", upload-time = 2026-04-02T09:27:15Z, size = 211564, hashes = { sha256 = "3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18" } }, { url = "https://files.pythonhosted.org/packages/44/86/58e6f13ce26cc3b8f4a36b94a0f22ae2f00a72534520f4ae6857c4b81f89/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_aarch64.whl", upload-time = 2026-04-02T09:27:16Z, size = 211276, hashes = { sha256 = "e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b" } }, { url = "https://files.pythonhosted.org/packages/8f/fe/d17c32dc72e17e155e06883efa84514ca375f8a528ba2546bee73fc4df81/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_armv7l.whl", upload-time = 2026-04-02T09:27:18Z, size = 201238, hashes = { sha256 = "a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356" } }, { url = "https://files.pythonhosted.org/packages/6a/29/f33daa50b06525a237451cdb6c69da366c381a3dadcd833fa5676bc468b3/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_ppc64le.whl", upload-time = 2026-04-02T09:27:19Z, size = 230189, hashes = { sha256 = "2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab" } }, { url = "https://files.pythonhosted.org/packages/b6/6e/52c84015394a6a0bdcd435210a7e944c5f94ea1055f5cc5d56c5fe368e7b/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_riscv64.whl", upload-time = 2026-04-02T09:27:20Z, size = 211352, hashes = { sha256 = "e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46" } }, { url = "https://files.pythonhosted.org/packages/8c/d7/4353be581b373033fb9198bf1da3cf8f09c1082561e8e922aa7b39bf9fe8/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_s390x.whl", upload-time = 2026-04-02T09:27:22Z, size = 227024, hashes = { sha256 = "d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44" } }, { url = "https://files.pythonhosted.org/packages/30/45/99d18aa925bd1740098ccd3060e238e21115fffbfdcb8f3ece837d0ace6c/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_x86_64.whl", upload-time = 2026-04-02T09:27:23Z, size = 217869, hashes = { sha256 = "7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72" } }, { url = "https://files.pythonhosted.org/packages/5c/05/5ee478aa53f4bb7996482153d4bfe1b89e0f087f0ab6b294fcf92d595873/charset_normalizer-3.4.7-cp314-cp314-win32.whl", upload-time = 2026-04-02T09:27:25Z, size = 148541, hashes = { sha256 = "5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10" } }, { url = "https://files.pythonhosted.org/packages/48/77/72dcb0921b2ce86420b2d79d454c7022bf5be40202a2a07906b9f2a35c97/charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl", upload-time = 2026-04-02T09:27:26Z, size = 159634, hashes = { sha256 = "92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f" } }, { url = "https://files.pythonhosted.org/packages/c6/a3/c2369911cd72f02386e4e340770f6e158c7980267da16af8f668217abaa0/charset_normalizer-3.4.7-cp314-cp314-win_arm64.whl", upload-time = 2026-04-02T09:27:28Z, size = 148384, hashes = { sha256 = "67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246" } }, { url = "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl", upload-time = 2026-04-02T09:27:29Z, size = 330133, hashes = { sha256 = "effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24" } }, { url = "https://files.pythonhosted.org/packages/8d/da/96975ddb11f8e977f706f45cddd8540fd8242f71ecdb5d18a80723dcf62c/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", upload-time = 2026-04-02T09:27:30Z, size = 216257, hashes = { sha256 = "fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79" } }, { url = "https://files.pythonhosted.org/packages/e5/e8/1d63bf8ef2d388e95c64b2098f45f84758f6d102a087552da1485912637b/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", upload-time = 2026-04-02T09:27:32Z, size = 234851, hashes = { sha256 = "733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960" } }, { url = "https://files.pythonhosted.org/packages/9b/40/e5ff04233e70da2681fa43969ad6f66ca5611d7e669be0246c4c7aaf6dc8/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", upload-time = 2026-04-02T09:27:34Z, size = 233393, hashes = { sha256 = "a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4" } }, { url = "https://files.pythonhosted.org/packages/be/c1/06c6c49d5a5450f76899992f1ee40b41d076aee9279b49cf9974d2f313d5/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", upload-time = 2026-04-02T09:27:35Z, size = 223251, hashes = { sha256 = "6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e" } }, { url = "https://files.pythonhosted.org/packages/2b/9f/f2ff16fb050946169e3e1f82134d107e5d4ae72647ec8a1b1446c148480f/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_armv7l.whl", upload-time = 2026-04-02T09:27:36Z, size = 206609, hashes = { sha256 = "a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1" } }, { url = "https://files.pythonhosted.org/packages/69/d5/a527c0cd8d64d2eab7459784fb4169a0ac76e5a6fc5237337982fd61347e/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", upload-time = 2026-04-02T09:27:38Z, size = 220014, hashes = { sha256 = "3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44" } }, { url = "https://files.pythonhosted.org/packages/7e/80/8a7b8104a3e203074dc9aa2c613d4b726c0e136bad1cc734594b02867972/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_aarch64.whl", upload-time = 2026-04-02T09:27:39Z, size = 218979, hashes = { sha256 = "8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e" } }, { url = "https://files.pythonhosted.org/packages/02/9a/b759b503d507f375b2b5c153e4d2ee0a75aa215b7f2489cf314f4541f2c0/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_armv7l.whl", upload-time = 2026-04-02T09:27:40Z, size = 209238, hashes = { sha256 = "cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3" } }, { url = "https://files.pythonhosted.org/packages/c2/4e/0f3f5d47b86bdb79256e7290b26ac847a2832d9a4033f7eb2cd4bcf4bb5b/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", upload-time = 2026-04-02T09:27:42Z, size = 236110, hashes = { sha256 = "0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0" } }, { url = "https://files.pythonhosted.org/packages/96/23/bce28734eb3ed2c91dcf93abeb8a5cf393a7b2749725030bb630e554fdd8/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_riscv64.whl", upload-time = 2026-04-02T09:27:43Z, size = 219824, hashes = { sha256 = "752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e" } }, { url = "https://files.pythonhosted.org/packages/2c/6f/6e897c6984cc4d41af319b077f2f600fc8214eb2fe2d6bcb79141b882400/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_s390x.whl", upload-time = 2026-04-02T09:27:45Z, size = 233103, hashes = { sha256 = "8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb" } }, { url = "https://files.pythonhosted.org/packages/76/22/ef7bd0fe480a0ae9b656189ec00744b60933f68b4f42a7bb06589f6f576a/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_x86_64.whl", upload-time = 2026-04-02T09:27:46Z, size = 225194, hashes = { sha256 = "ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe" } }, { url = "https://files.pythonhosted.org/packages/c5/a7/0e0ab3e0b5bc1219bd80a6a0d4d72ca74d9250cb2382b7c699c147e06017/charset_normalizer-3.4.7-cp314-cp314t-win32.whl", upload-time = 2026-04-02T09:27:48Z, size = 159827, hashes = { sha256 = "c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0" } }, { url = "https://files.pythonhosted.org/packages/7a/1d/29d32e0fb40864b1f878c7f5a0b343ae676c6e2b271a2d55cc3a152391da/charset_normalizer-3.4.7-cp314-cp314t-win_amd64.whl", upload-time = 2026-04-02T09:27:49Z, size = 174168, hashes = { sha256 = "03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c" } }, { url = "https://files.pythonhosted.org/packages/de/32/d92444ad05c7a6e41fb2036749777c163baf7a0301a040cb672d6b2b1ae9/charset_normalizer-3.4.7-cp314-cp314t-win_arm64.whl", upload-time = 2026-04-02T09:27:51Z, size = 153018, hashes = { sha256 = "c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d" } }, { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", upload-time = 2026-04-02T09:28:37Z, size = 61958, hashes = { sha256 = "3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d" } }, ] [[packages]] name = "cryptography" version = "46.0.6" sdist = { url = "https://files.pythonhosted.org/packages/a4/ba/04b1bd4218cbc58dc90ce967106d51582371b898690f3ae0402876cc4f34/cryptography-46.0.6.tar.gz", upload-time = 2026-03-25T23:34:53Z, size = 750542, hashes = { sha256 = "27550628a518c5c6c903d84f637fbecf287f6cb9ced3804838a1295dc1fd0759" } } wheels = [ { url = "https://files.pythonhosted.org/packages/47/23/9285e15e3bc57325b0a72e592921983a701efc1ee8f91c06c5f0235d86d9/cryptography-46.0.6-cp311-abi3-macosx_10_9_universal2.whl", upload-time = 2026-03-25T23:33:22Z, size = 7176401, hashes = { sha256 = "64235194bad039a10bb6d2d930ab3323baaec67e2ce36215fd0952fad0930ca8" } }, { url = "https://files.pythonhosted.org/packages/60/f8/e61f8f13950ab6195b31913b42d39f0f9afc7d93f76710f299b5ec286ae6/cryptography-46.0.6-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", upload-time = 2026-03-25T23:33:23Z, size = 4275275, hashes = { sha256 = "26031f1e5ca62fcb9d1fcb34b2b60b390d1aacaa15dc8b895a9ed00968b97b30" } }, { url = "https://files.pythonhosted.org/packages/19/69/732a736d12c2631e140be2348b4ad3d226302df63ef64d30dfdb8db7ad1c/cryptography-46.0.6-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", upload-time = 2026-03-25T23:33:25Z, size = 4425320, hashes = { sha256 = "9a693028b9cbe51b5a1136232ee8f2bc242e4e19d456ded3fa7c86e43c713b4a" } }, { url = "https://files.pythonhosted.org/packages/d4/12/123be7292674abf76b21ac1fc0e1af50661f0e5b8f0ec8285faac18eb99e/cryptography-46.0.6-cp311-abi3-manylinux_2_28_aarch64.whl", upload-time = 2026-03-25T23:33:27Z, size = 4278082, hashes = { sha256 = "67177e8a9f421aa2d3a170c3e56eca4e0128883cf52a071a7cbf53297f18b175" } }, { url = "https://files.pythonhosted.org/packages/5b/ba/d5e27f8d68c24951b0a484924a84c7cdaed7502bac9f18601cd357f8b1d2/cryptography-46.0.6-cp311-abi3-manylinux_2_28_ppc64le.whl", upload-time = 2026-03-25T23:33:29Z, size = 4926514, hashes = { sha256 = "d9528b535a6c4f8ff37847144b8986a9a143585f0540fbcb1a98115b543aa463" } }, { url = "https://files.pythonhosted.org/packages/34/71/1ea5a7352ae516d5512d17babe7e1b87d9db5150b21f794b1377eac1edc0/cryptography-46.0.6-cp311-abi3-manylinux_2_28_x86_64.whl", upload-time = 2026-03-25T23:33:30Z, size = 4457766, hashes = { sha256 = "22259338084d6ae497a19bae5d4c66b7ca1387d3264d1c2c0e72d9e9b6a77b97" } }, { url = "https://files.pythonhosted.org/packages/01/59/562be1e653accee4fdad92c7a2e88fced26b3fdfce144047519bbebc299e/cryptography-46.0.6-cp311-abi3-manylinux_2_31_armv7l.whl", upload-time = 2026-03-25T23:33:33Z, size = 3986535, hashes = { sha256 = "760997a4b950ff00d418398ad73fbc91aa2894b5c1db7ccb45b4f68b42a63b3c" } }, { url = "https://files.pythonhosted.org/packages/d6/8b/b1ebfeb788bf4624d36e45ed2662b8bd43a05ff62157093c1539c1288a18/cryptography-46.0.6-cp311-abi3-manylinux_2_34_aarch64.whl", upload-time = 2026-03-25T23:33:34Z, size = 4277618, hashes = { sha256 = "3dfa6567f2e9e4c5dceb8ccb5a708158a2a871052fa75c8b78cb0977063f1507" } }, { url = "https://files.pythonhosted.org/packages/dd/52/a005f8eabdb28df57c20f84c44d397a755782d6ff6d455f05baa2785bd91/cryptography-46.0.6-cp311-abi3-manylinux_2_34_ppc64le.whl", upload-time = 2026-03-25T23:33:37Z, size = 4890802, hashes = { sha256 = "cdcd3edcbc5d55757e5f5f3d330dd00007ae463a7e7aa5bf132d1f22a4b62b19" } }, { url = "https://files.pythonhosted.org/packages/ec/4d/8e7d7245c79c617d08724e2efa397737715ca0ec830ecb3c91e547302555/cryptography-46.0.6-cp311-abi3-manylinux_2_34_x86_64.whl", upload-time = 2026-03-25T23:33:38Z, size = 4457425, hashes = { sha256 = "d4e4aadb7fc1f88687f47ca20bb7227981b03afaae69287029da08096853b738" } }, { url = "https://files.pythonhosted.org/packages/1d/5c/f6c3596a1430cec6f949085f0e1a970638d76f81c3ea56d93d564d04c340/cryptography-46.0.6-cp311-abi3-musllinux_1_2_aarch64.whl", upload-time = 2026-03-25T23:33:40Z, size = 4405530, hashes = { sha256 = "2b417edbe8877cda9022dde3a008e2deb50be9c407eef034aeeb3a8b11d9db3c" } }, { url = "https://files.pythonhosted.org/packages/7e/c9/9f9cea13ee2dbde070424e0c4f621c091a91ffcc504ffea5e74f0e1daeff/cryptography-46.0.6-cp311-abi3-musllinux_1_2_x86_64.whl", upload-time = 2026-03-25T23:33:42Z, size = 4667896, hashes = { sha256 = "380343e0653b1c9d7e1f55b52aaa2dbb2fdf2730088d48c43ca1c7c0abb7cc2f" } }, { url = "https://files.pythonhosted.org/packages/ad/b5/1895bc0821226f129bc74d00eccfc6a5969e2028f8617c09790bf89c185e/cryptography-46.0.6-cp311-abi3-win32.whl", upload-time = 2026-03-25T23:33:45Z, size = 3026348, hashes = { sha256 = "bcb87663e1f7b075e48c3be3ecb5f0b46c8fc50b50a97cf264e7f60242dca3f2" } }, { url = "https://files.pythonhosted.org/packages/c3/f8/c9bcbf0d3e6ad288b9d9aa0b1dee04b063d19e8c4f871855a03ab3a297ab/cryptography-46.0.6-cp311-abi3-win_amd64.whl", upload-time = 2026-03-25T23:33:46Z, size = 3483896, hashes = { sha256 = "6739d56300662c468fddb0e5e291f9b4d084bead381667b9e654c7dd81705124" } }, { url = "https://files.pythonhosted.org/packages/01/41/3a578f7fd5c70611c0aacba52cd13cb364a5dee895a5c1d467208a9380b0/cryptography-46.0.6-cp314-cp314t-macosx_10_9_universal2.whl", upload-time = 2026-03-25T23:33:48Z, size = 7117147, hashes = { sha256 = "2ef9e69886cbb137c2aef9772c2e7138dc581fad4fcbcf13cc181eb5a3ab6275" } }, { url = "https://files.pythonhosted.org/packages/fa/87/887f35a6fca9dde90cad08e0de0c89263a8e59b2d2ff904fd9fcd8025b6f/cryptography-46.0.6-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", upload-time = 2026-03-25T23:33:49Z, size = 4266221, hashes = { sha256 = "7f417f034f91dcec1cb6c5c35b07cdbb2ef262557f701b4ecd803ee8cefed4f4" } }, { url = "https://files.pythonhosted.org/packages/aa/a8/0a90c4f0b0871e0e3d1ed126aed101328a8a57fd9fd17f00fb67e82a51ca/cryptography-46.0.6-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", upload-time = 2026-03-25T23:33:52Z, size = 4408952, hashes = { sha256 = "d24c13369e856b94892a89ddf70b332e0b70ad4a5c43cf3e9cb71d6d7ffa1f7b" } }, { url = "https://files.pythonhosted.org/packages/16/0b/b239701eb946523e4e9f329336e4ff32b1247e109cbab32d1a7b61da8ed7/cryptography-46.0.6-cp314-cp314t-manylinux_2_28_aarch64.whl", upload-time = 2026-03-25T23:33:54Z, size = 4270141, hashes = { sha256 = "aad75154a7ac9039936d50cf431719a2f8d4ed3d3c277ac03f3339ded1a5e707" } }, { url = "https://files.pythonhosted.org/packages/0f/a8/976acdd4f0f30df7b25605f4b9d3d89295351665c2091d18224f7ad5cdbf/cryptography-46.0.6-cp314-cp314t-manylinux_2_28_ppc64le.whl", upload-time = 2026-03-25T23:33:55Z, size = 4904178, hashes = { sha256 = "3c21d92ed15e9cfc6eb64c1f5a0326db22ca9c2566ca46d845119b45b4400361" } }, { url = "https://files.pythonhosted.org/packages/b1/1b/bf0e01a88efd0e59679b69f42d4afd5bced8700bb5e80617b2d63a3741af/cryptography-46.0.6-cp314-cp314t-manylinux_2_28_x86_64.whl", upload-time = 2026-03-25T23:33:57Z, size = 4441812, hashes = { sha256 = "4668298aef7cddeaf5c6ecc244c2302a2b8e40f384255505c22875eebb47888b" } }, { url = "https://files.pythonhosted.org/packages/bb/8b/11df86de2ea389c65aa1806f331cae145f2ed18011f30234cc10ca253de8/cryptography-46.0.6-cp314-cp314t-manylinux_2_31_armv7l.whl", upload-time = 2026-03-25T23:33:59Z, size = 3963923, hashes = { sha256 = "8ce35b77aaf02f3b59c90b2c8a05c73bac12cea5b4e8f3fbece1f5fddea5f0ca" } }, { url = "https://files.pythonhosted.org/packages/91/e0/207fb177c3a9ef6a8108f234208c3e9e76a6aa8cf20d51932916bd43bda0/cryptography-46.0.6-cp314-cp314t-manylinux_2_34_aarch64.whl", upload-time = 2026-03-25T23:34:00Z, size = 4269695, hashes = { sha256 = "c89eb37fae9216985d8734c1afd172ba4927f5a05cfd9bf0e4863c6d5465b013" } }, { url = "https://files.pythonhosted.org/packages/21/5e/19f3260ed1e95bced52ace7501fabcd266df67077eeb382b79c81729d2d3/cryptography-46.0.6-cp314-cp314t-manylinux_2_34_ppc64le.whl", upload-time = 2026-03-25T23:34:02Z, size = 4869785, hashes = { sha256 = "ed418c37d095aeddf5336898a132fba01091f0ac5844e3e8018506f014b6d2c4" } }, { url = "https://files.pythonhosted.org/packages/10/38/cd7864d79aa1d92ef6f1a584281433419b955ad5a5ba8d1eb6c872165bcb/cryptography-46.0.6-cp314-cp314t-manylinux_2_34_x86_64.whl", upload-time = 2026-03-25T23:34:04Z, size = 4441404, hashes = { sha256 = "69cf0056d6947edc6e6760e5f17afe4bea06b56a9ac8a06de9d2bd6b532d4f3a" } }, { url = "https://files.pythonhosted.org/packages/09/0a/4fe7a8d25fed74419f91835cf5829ade6408fd1963c9eae9c4bce390ecbb/cryptography-46.0.6-cp314-cp314t-musllinux_1_2_aarch64.whl", upload-time = 2026-03-25T23:34:06Z, size = 4397549, hashes = { sha256 = "8e7304c4f4e9490e11efe56af6713983460ee0780f16c63f219984dab3af9d2d" } }, { url = "https://files.pythonhosted.org/packages/5f/a0/7d738944eac6513cd60a8da98b65951f4a3b279b93479a7e8926d9cd730b/cryptography-46.0.6-cp314-cp314t-musllinux_1_2_x86_64.whl", upload-time = 2026-03-25T23:34:07Z, size = 4651874, hashes = { sha256 = "b928a3ca837c77a10e81a814a693f2295200adb3352395fad024559b7be7a736" } }, { url = "https://files.pythonhosted.org/packages/cb/f1/c2326781ca05208845efca38bf714f76939ae446cd492d7613808badedf1/cryptography-46.0.6-cp314-cp314t-win32.whl", upload-time = 2026-03-25T23:34:09Z, size = 3001511, hashes = { sha256 = "97c8115b27e19e592a05c45d0dd89c57f81f841cc9880e353e0d3bf25b2139ed" } }, { url = "https://files.pythonhosted.org/packages/c9/57/fe4a23eb549ac9d903bd4698ffda13383808ef0876cc912bcb2838799ece/cryptography-46.0.6-cp314-cp314t-win_amd64.whl", upload-time = 2026-03-25T23:34:11Z, size = 3471692, hashes = { sha256 = "c797e2517cb7880f8297e2c0f43bb910e91381339336f75d2c1c2cbf811b70b4" } }, { url = "https://files.pythonhosted.org/packages/c4/cc/f330e982852403da79008552de9906804568ae9230da8432f7496ce02b71/cryptography-46.0.6-cp38-abi3-macosx_10_9_universal2.whl", upload-time = 2026-03-25T23:34:13Z, size = 7162776, hashes = { sha256 = "12cae594e9473bca1a7aceb90536060643128bb274fcea0fc459ab90f7d1ae7a" } }, { url = "https://files.pythonhosted.org/packages/49/b3/dc27efd8dcc4bff583b3f01d4a3943cd8b5821777a58b3a6a5f054d61b79/cryptography-46.0.6-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", upload-time = 2026-03-25T23:34:15Z, size = 4270529, hashes = { sha256 = "639301950939d844a9e1c4464d7e07f902fe9a7f6b215bb0d4f28584729935d8" } }, { url = "https://files.pythonhosted.org/packages/e6/05/e8d0e6eb4f0d83365b3cb0e00eb3c484f7348db0266652ccd84632a3d58d/cryptography-46.0.6-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", upload-time = 2026-03-25T23:34:16Z, size = 4414827, hashes = { sha256 = "ed3775295fb91f70b4027aeba878d79b3e55c0b3e97eaa4de71f8f23a9f2eb77" } }, { url = "https://files.pythonhosted.org/packages/2f/97/daba0f5d2dc6d855e2dcb70733c812558a7977a55dd4a6722756628c44d1/cryptography-46.0.6-cp38-abi3-manylinux_2_28_aarch64.whl", upload-time = 2026-03-25T23:34:18Z, size = 4271265, hashes = { sha256 = "8927ccfbe967c7df312ade694f987e7e9e22b2425976ddbf28271d7e58845290" } }, { url = "https://files.pythonhosted.org/packages/89/06/fe1fce39a37ac452e58d04b43b0855261dac320a2ebf8f5260dd55b201a9/cryptography-46.0.6-cp38-abi3-manylinux_2_28_ppc64le.whl", upload-time = 2026-03-25T23:34:20Z, size = 4916800, hashes = { sha256 = "b12c6b1e1651e42ab5de8b1e00dc3b6354fdfd778e7fa60541ddacc27cd21410" } }, { url = "https://files.pythonhosted.org/packages/ff/8a/b14f3101fe9c3592603339eb5d94046c3ce5f7fc76d6512a2d40efd9724e/cryptography-46.0.6-cp38-abi3-manylinux_2_28_x86_64.whl", upload-time = 2026-03-25T23:34:22Z, size = 4448771, hashes = { sha256 = "063b67749f338ca9c5a0b7fe438a52c25f9526b851e24e6c9310e7195aad3b4d" } }, { url = "https://files.pythonhosted.org/packages/01/b3/0796998056a66d1973fd52ee89dc1bb3b6581960a91ad4ac705f182d398f/cryptography-46.0.6-cp38-abi3-manylinux_2_31_armv7l.whl", upload-time = 2026-03-25T23:34:24Z, size = 3978333, hashes = { sha256 = "02fad249cb0e090b574e30b276a3da6a149e04ee2f049725b1f69e7b8351ec70" } }, { url = "https://files.pythonhosted.org/packages/c5/3d/db200af5a4ffd08918cd55c08399dc6c9c50b0bc72c00a3246e099d3a849/cryptography-46.0.6-cp38-abi3-manylinux_2_34_aarch64.whl", upload-time = 2026-03-25T23:34:25Z, size = 4271069, hashes = { sha256 = "7e6142674f2a9291463e5e150090b95a8519b2fb6e6aaec8917dd8d094ce750d" } }, { url = "https://files.pythonhosted.org/packages/d7/18/61acfd5b414309d74ee838be321c636fe71815436f53c9f0334bf19064fa/cryptography-46.0.6-cp38-abi3-manylinux_2_34_ppc64le.whl", upload-time = 2026-03-25T23:34:27Z, size = 4878358, hashes = { sha256 = "456b3215172aeefb9284550b162801d62f5f264a081049a3e94307fe20792cfa" } }, { url = "https://files.pythonhosted.org/packages/8b/65/5bf43286d566f8171917cae23ac6add941654ccf085d739195a4eacf1674/cryptography-46.0.6-cp38-abi3-manylinux_2_34_x86_64.whl", upload-time = 2026-03-25T23:34:29Z, size = 4448061, hashes = { sha256 = "341359d6c9e68834e204ceaf25936dffeafea3829ab80e9503860dcc4f4dac58" } }, { url = "https://files.pythonhosted.org/packages/e0/25/7e49c0fa7205cf3597e525d156a6bce5b5c9de1fd7e8cb01120e459f205a/cryptography-46.0.6-cp38-abi3-musllinux_1_2_aarch64.whl", upload-time = 2026-03-25T23:34:32Z, size = 4399103, hashes = { sha256 = "9a9c42a2723999a710445bc0d974e345c32adfd8d2fac6d8a251fa829ad31cfb" } }, { url = "https://files.pythonhosted.org/packages/44/46/466269e833f1c4718d6cd496ffe20c56c9c8d013486ff66b4f69c302a68d/cryptography-46.0.6-cp38-abi3-musllinux_1_2_x86_64.whl", upload-time = 2026-03-25T23:34:33Z, size = 4659255, hashes = { sha256 = "6617f67b1606dfd9fe4dbfa354a9508d4a6d37afe30306fe6c101b7ce3274b72" } }, { url = "https://files.pythonhosted.org/packages/0a/09/ddc5f630cc32287d2c953fc5d32705e63ec73e37308e5120955316f53827/cryptography-46.0.6-cp38-abi3-win32.whl", upload-time = 2026-03-25T23:34:35Z, size = 3010660, hashes = { sha256 = "7f6690b6c55e9c5332c0b59b9c8a3fb232ebf059094c17f9019a51e9827df91c" } }, { url = "https://files.pythonhosted.org/packages/1b/82/ca4893968aeb2709aacfb57a30dec6fa2ab25b10fa9f064b8882ce33f599/cryptography-46.0.6-cp38-abi3-win_amd64.whl", upload-time = 2026-03-25T23:34:37Z, size = 3471160, hashes = { sha256 = "79e865c642cfc5c0b3eb12af83c35c5aeff4fa5c672dc28c43721c2c9fdd2f0f" } }, ] [[packages]] name = "idna" version = "3.11" sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", upload-time = 2025-10-12T14:55:20Z, size = 194582, hashes = { sha256 = "795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902" } } wheels = [{ url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", upload-time = 2025-10-12T14:55:18Z, size = 71008, hashes = { sha256 = "771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea" } }] [[packages]] name = "pycparser" version = "3.0" marker = "python_full_version >= '3.9' and implementation_name != 'PyPy' and platform_python_implementation != 'PyPy'" sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", upload-time = 2026-01-21T14:26:51Z, size = 103492, hashes = { sha256 = "600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29" } } wheels = [{ url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", upload-time = 2026-01-21T14:26:50Z, size = 48172, hashes = { sha256 = "b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992" } }] [[packages]] name = "pydantic" version = "2.12.5" sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", upload-time = 2025-11-26T15:11:46Z, size = 821591, hashes = { sha256 = "4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49" } } wheels = [{ url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", upload-time = 2025-11-26T15:11:44Z, size = 463580, hashes = { sha256 = "e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d" } }] [[packages]] name = "pydantic-core" version = "2.41.5" sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", upload-time = 2025-11-04T13:43:49Z, size = 460952, hashes = { sha256 = "08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e" } } wheels = [ { url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", upload-time = 2025-11-04T13:40:25Z, size = 2120403, hashes = { sha256 = "941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9" } }, { url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", upload-time = 2025-11-04T13:40:27Z, size = 1896206, hashes = { sha256 = "112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34" } }, { url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", upload-time = 2025-11-04T13:40:29Z, size = 1919307, hashes = { sha256 = "0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0" } }, { url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", upload-time = 2025-11-04T13:40:33Z, size = 2063258, hashes = { sha256 = "03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33" } }, { url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", upload-time = 2025-11-04T13:40:35Z, size = 2214917, hashes = { sha256 = "dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e" } }, { url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", upload-time = 2025-11-04T13:40:37Z, size = 2332186, hashes = { sha256 = "97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2" } }, { url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", upload-time = 2025-11-04T13:40:40Z, size = 2073164, hashes = { sha256 = "406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586" } }, { url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", upload-time = 2025-11-04T13:40:42Z, size = 2179146, hashes = { sha256 = "b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d" } }, { url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", upload-time = 2025-11-04T13:40:44Z, size = 2137788, hashes = { sha256 = "01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740" } }, { url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", upload-time = 2025-11-04T13:40:46Z, size = 2340133, hashes = { sha256 = "6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e" } }, { url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", upload-time = 2025-11-04T13:40:48Z, size = 2324852, hashes = { sha256 = "915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858" } }, { url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", upload-time = 2025-11-04T13:40:50Z, size = 1994679, hashes = { sha256 = "650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36" } }, { url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", upload-time = 2025-11-04T13:40:52Z, size = 2019766, hashes = { sha256 = "79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11" } }, { url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", upload-time = 2025-11-04T13:40:54Z, size = 1981005, hashes = { sha256 = "3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd" } }, { url = "https://files.pythonhosted.org/packages/ea/28/46b7c5c9635ae96ea0fbb779e271a38129df2550f763937659ee6c5dbc65/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", upload-time = 2025-11-04T13:40:56Z, size = 2119622, hashes = { sha256 = "3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a" } }, { url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", upload-time = 2025-11-04T13:40:58Z, size = 1891725, hashes = { sha256 = "1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14" } }, { url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", upload-time = 2025-11-04T13:41:00Z, size = 1915040, hashes = { sha256 = "25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1" } }, { url = "https://files.pythonhosted.org/packages/84/a3/15a82ac7bd97992a82257f777b3583d3e84bdb06ba6858f745daa2ec8a85/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", upload-time = 2025-11-04T13:41:03Z, size = 2063691, hashes = { sha256 = "506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66" } }, { url = "https://files.pythonhosted.org/packages/74/9b/0046701313c6ef08c0c1cf0e028c67c770a4e1275ca73131563c5f2a310a/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", upload-time = 2025-11-04T13:41:05Z, size = 2213897, hashes = { sha256 = "4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869" } }, { url = "https://files.pythonhosted.org/packages/8a/cd/6bac76ecd1b27e75a95ca3a9a559c643b3afcd2dd62086d4b7a32a18b169/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", upload-time = 2025-11-04T13:41:07Z, size = 2333302, hashes = { sha256 = "2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2" } }, { url = "https://files.pythonhosted.org/packages/4c/d2/ef2074dc020dd6e109611a8be4449b98cd25e1b9b8a303c2f0fca2f2bcf7/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", upload-time = 2025-11-04T13:41:09Z, size = 2064877, hashes = { sha256 = "22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375" } }, { url = "https://files.pythonhosted.org/packages/18/66/e9db17a9a763d72f03de903883c057b2592c09509ccfe468187f2a2eef29/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", upload-time = 2025-11-04T13:41:12Z, size = 2180680, hashes = { sha256 = "2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553" } }, { url = "https://files.pythonhosted.org/packages/d3/9e/3ce66cebb929f3ced22be85d4c2399b8e85b622db77dad36b73c5387f8f8/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", upload-time = 2025-11-04T13:41:14Z, size = 2138960, hashes = { sha256 = "0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90" } }, { url = "https://files.pythonhosted.org/packages/a6/62/205a998f4327d2079326b01abee48e502ea739d174f0a89295c481a2272e/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", upload-time = 2025-11-04T13:41:16Z, size = 2339102, hashes = { sha256 = "63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07" } }, { url = "https://files.pythonhosted.org/packages/3c/0d/f05e79471e889d74d3d88f5bd20d0ed189ad94c2423d81ff8d0000aab4ff/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", upload-time = 2025-11-04T13:41:18Z, size = 2326039, hashes = { sha256 = "e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb" } }, { url = "https://files.pythonhosted.org/packages/ec/e1/e08a6208bb100da7e0c4b288eed624a703f4d129bde2da475721a80cab32/pydantic_core-2.41.5-cp314-cp314-win32.whl", upload-time = 2025-11-04T13:41:21Z, size = 1995126, hashes = { sha256 = "aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23" } }, { url = "https://files.pythonhosted.org/packages/48/5d/56ba7b24e9557f99c9237e29f5c09913c81eeb2f3217e40e922353668092/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", upload-time = 2025-11-04T13:41:24Z, size = 2015489, hashes = { sha256 = "8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf" } }, { url = "https://files.pythonhosted.org/packages/4e/bb/f7a190991ec9e3e0ba22e4993d8755bbc4a32925c0b5b42775c03e8148f9/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", upload-time = 2025-11-04T13:41:26Z, size = 1977288, hashes = { sha256 = "e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0" } }, { url = "https://files.pythonhosted.org/packages/92/ed/77542d0c51538e32e15afe7899d79efce4b81eee631d99850edc2f5e9349/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", upload-time = 2025-11-04T13:41:28Z, size = 2120255, hashes = { sha256 = "8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a" } }, { url = "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", upload-time = 2025-11-04T13:41:31Z, size = 1863760, hashes = { sha256 = "b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3" } }, { url = "https://files.pythonhosted.org/packages/5a/f0/e5e6b99d4191da102f2b0eb9687aaa7f5bea5d9964071a84effc3e40f997/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", upload-time = 2025-11-04T13:41:33Z, size = 1878092, hashes = { sha256 = "3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c" } }, { url = "https://files.pythonhosted.org/packages/71/48/36fb760642d568925953bcc8116455513d6e34c4beaa37544118c36aba6d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", upload-time = 2025-11-04T13:41:35Z, size = 2053385, hashes = { sha256 = "72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612" } }, { url = "https://files.pythonhosted.org/packages/20/25/92dc684dd8eb75a234bc1c764b4210cf2646479d54b47bf46061657292a8/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", upload-time = 2025-11-04T13:41:37Z, size = 2218832, hashes = { sha256 = "5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d" } }, { url = "https://files.pythonhosted.org/packages/e2/09/f53e0b05023d3e30357d82eb35835d0f6340ca344720a4599cd663dca599/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", upload-time = 2025-11-04T13:41:40Z, size = 2327585, hashes = { sha256 = "bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9" } }, { url = "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", upload-time = 2025-11-04T13:41:42Z, size = 2041078, hashes = { sha256 = "2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660" } }, { url = "https://files.pythonhosted.org/packages/cd/13/2e215f17f0ef326fc72afe94776edb77525142c693767fc347ed6288728d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", upload-time = 2025-11-04T13:41:45Z, size = 2173914, hashes = { sha256 = "d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9" } }, { url = "https://files.pythonhosted.org/packages/02/7a/f999a6dcbcd0e5660bc348a3991c8915ce6599f4f2c6ac22f01d7a10816c/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", upload-time = 2025-11-04T13:41:47Z, size = 2129560, hashes = { sha256 = "a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3" } }, { url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", upload-time = 2025-11-04T13:41:49Z, size = 2329244, hashes = { sha256 = "239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf" } }, { url = "https://files.pythonhosted.org/packages/d9/02/3c562f3a51afd4d88fff8dffb1771b30cfdfd79befd9883ee094f5b6c0d8/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", upload-time = 2025-11-04T13:41:54Z, size = 2331955, hashes = { sha256 = "2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470" } }, { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", upload-time = 2025-11-04T13:41:56Z, size = 1988906, hashes = { sha256 = "b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa" } }, { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", upload-time = 2025-11-04T13:41:58Z, size = 1981607, hashes = { sha256 = "80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c" } }, { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", upload-time = 2025-11-04T13:42:01Z, size = 1974769, hashes = { sha256 = "35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008" } }, ] [[packages]] name = "pydantic-settings" version = "2.13.1" sdist = { url = "https://files.pythonhosted.org/packages/52/6d/fffca34caecc4a3f97bda81b2098da5e8ab7efc9a66e819074a11955d87e/pydantic_settings-2.13.1.tar.gz", upload-time = 2026-02-19T13:45:08Z, size = 223826, hashes = { sha256 = "b4c11847b15237fb0171e1462bf540e294affb9b86db4d9aa5c01730bdbe4025" } } wheels = [{ url = "https://files.pythonhosted.org/packages/00/4b/ccc026168948fec4f7555b9164c724cf4125eac006e176541483d2c959be/pydantic_settings-2.13.1-py3-none-any.whl", upload-time = 2026-02-19T13:45:06Z, size = 58929, hashes = { sha256 = "d56fd801823dbeae7f0975e1f8c8e25c258eb75d278ea7abb5d9cebb01b56237" } }] [[packages]] name = "pygithub" version = "2.9.0" sdist = { url = "https://files.pythonhosted.org/packages/a6/9a/44f918e9be12e49cb8b053f09d5d0733b74df52bf4dabc570da1c3ecd9f6/pygithub-2.9.0.tar.gz", upload-time = 2026-03-22T21:14:39Z, size = 2592289, hashes = { sha256 = "a26abda1222febba31238682634cad11d8b966137ed6cc3c5e445b29a11cb0a4" } } wheels = [{ url = "https://files.pythonhosted.org/packages/2f/de/72e02bc7674e161b155a4b5a03b2347129d0626115bc97ba5bad5070cac9/pygithub-2.9.0-py3-none-any.whl", upload-time = 2026-03-22T21:14:37Z, size = 449653, hashes = { sha256 = "5e2b260ce327bffce9b00f447b65953ef7078ffe93e5a5425624a3075483927c" } }] [[packages]] name = "pyjwt" version = "2.12.1" sdist = { url = "https://files.pythonhosted.org/packages/c2/27/a3b6e5bf6ff856d2509292e95c8f57f0df7017cf5394921fc4e4ef40308a/pyjwt-2.12.1.tar.gz", upload-time = 2026-03-13T19:27:37Z, size = 102564, hashes = { sha256 = "c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b" } } wheels = [{ url = "https://files.pythonhosted.org/packages/e5/7a/8dd906bd22e79e47397a61742927f6747fe93242ef86645ee9092e610244/pyjwt-2.12.1-py3-none-any.whl", upload-time = 2026-03-13T19:27:35Z, size = 29726, hashes = { sha256 = "28ca37c070cad8ba8cd9790cd940535d40274d22f80ab87f3ac6a713e6e8454c" } }] [[packages]] name = "pynacl" version = "1.6.2" sdist = { url = "https://files.pythonhosted.org/packages/d9/9a/4019b524b03a13438637b11538c82781a5eda427394380381af8f04f467a/pynacl-1.6.2.tar.gz", upload-time = 2026-01-01T17:48:10Z, size = 3511692, hashes = { sha256 = "018494d6d696ae03c7e656e5e74cdfd8ea1326962cc401bcf018f1ed8436811c" } } wheels = [ { url = "https://files.pythonhosted.org/packages/4b/79/0e3c34dc3c4671f67d251c07aa8eb100916f250ee470df230b0ab89551b4/pynacl-1.6.2-cp314-cp314t-macosx_10_10_universal2.whl", upload-time = 2026-01-01T17:31:57Z, size = 390064, hashes = { sha256 = "622d7b07cc5c02c666795792931b50c91f3ce3c2649762efb1ef0d5684c81594" } }, { url = "https://files.pythonhosted.org/packages/eb/1c/23a26e931736e13b16483795c8a6b2f641bf6a3d5238c22b070a5112722c/pynacl-1.6.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", upload-time = 2026-01-01T17:31:59Z, size = 809370, hashes = { sha256 = "d071c6a9a4c94d79eb665db4ce5cedc537faf74f2355e4d502591d850d3913c0" } }, { url = "https://files.pythonhosted.org/packages/87/74/8d4b718f8a22aea9e8dcc8b95deb76d4aae380e2f5b570cc70b5fd0a852d/pynacl-1.6.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", upload-time = 2026-01-01T17:32:01Z, size = 1408304, hashes = { sha256 = "fe9847ca47d287af41e82be1dd5e23023d3c31a951da134121ab02e42ac218c9" } }, { url = "https://files.pythonhosted.org/packages/fd/73/be4fdd3a6a87fe8a4553380c2b47fbd1f7f58292eb820902f5c8ac7de7b0/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", upload-time = 2026-01-01T17:32:02Z, size = 844871, hashes = { sha256 = "04316d1fc625d860b6c162fff704eb8426b1a8bcd3abacea11142cbd99a6b574" } }, { url = "https://files.pythonhosted.org/packages/55/ad/6efc57ab75ee4422e96b5f2697d51bbcf6cdcc091e66310df91fbdc144a8/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", upload-time = 2026-01-01T17:32:04Z, size = 1446356, hashes = { sha256 = "44081faff368d6c5553ccf55322ef2819abb40e25afaec7e740f159f74813634" } }, { url = "https://files.pythonhosted.org/packages/78/b7/928ee9c4779caa0a915844311ab9fb5f99585621c5d6e4574538a17dca07/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_aarch64.whl", upload-time = 2026-01-01T17:32:06Z, size = 826814, hashes = { sha256 = "a9f9932d8d2811ce1a8ffa79dcbdf3970e7355b5c8eb0c1a881a57e7f7d96e88" } }, { url = "https://files.pythonhosted.org/packages/f7/a9/1bdba746a2be20f8809fee75c10e3159d75864ef69c6b0dd168fc60e485d/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_x86_64.whl", upload-time = 2026-01-01T17:32:07Z, size = 1411742, hashes = { sha256 = "bc4a36b28dd72fb4845e5d8f9760610588a96d5a51f01d84d8c6ff9849968c14" } }, { url = "https://files.pythonhosted.org/packages/f3/2f/5e7ea8d85f9f3ea5b6b87db1d8388daa3587eed181bdeb0306816fdbbe79/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_aarch64.whl", upload-time = 2026-01-01T17:32:09Z, size = 801714, hashes = { sha256 = "3bffb6d0f6becacb6526f8f42adfb5efb26337056ee0831fb9a7044d1a964444" } }, { url = "https://files.pythonhosted.org/packages/06/ea/43fe2f7eab5f200e40fb10d305bf6f87ea31b3bbc83443eac37cd34a9e1e/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_x86_64.whl", upload-time = 2026-01-01T17:32:11Z, size = 1372257, hashes = { sha256 = "2fef529ef3ee487ad8113d287a593fa26f48ee3620d92ecc6f1d09ea38e0709b" } }, { url = "https://files.pythonhosted.org/packages/4d/54/c9ea116412788629b1347e415f72195c25eb2f3809b2d3e7b25f5c79f13a/pynacl-1.6.2-cp314-cp314t-win32.whl", upload-time = 2026-01-01T17:32:12Z, size = 231319, hashes = { sha256 = "a84bf1c20339d06dc0c85d9aea9637a24f718f375d861b2668b2f9f96fa51145" } }, { url = "https://files.pythonhosted.org/packages/ce/04/64e9d76646abac2dccf904fccba352a86e7d172647557f35b9fe2a5ee4a1/pynacl-1.6.2-cp314-cp314t-win_amd64.whl", upload-time = 2026-01-01T17:32:13Z, size = 244044, hashes = { sha256 = "320ef68a41c87547c91a8b58903c9caa641ab01e8512ce291085b5fe2fcb7590" } }, { url = "https://files.pythonhosted.org/packages/33/33/7873dc161c6a06f43cda13dec67b6fe152cb2f982581151956fa5e5cdb47/pynacl-1.6.2-cp314-cp314t-win_arm64.whl", upload-time = 2026-01-01T17:32:15Z, size = 188740, hashes = { sha256 = "d29bfe37e20e015a7d8b23cfc8bd6aa7909c92a1b8f41ee416bbb3e79ef182b2" } }, { url = "https://files.pythonhosted.org/packages/be/7b/4845bbf88e94586ec47a432da4e9107e3fc3ce37eb412b1398630a37f7dd/pynacl-1.6.2-cp38-abi3-macosx_10_10_universal2.whl", upload-time = 2026-01-01T17:32:16Z, size = 388458, hashes = { sha256 = "c949ea47e4206af7c8f604b8278093b674f7c79ed0d4719cc836902bf4517465" } }, { url = "https://files.pythonhosted.org/packages/1e/b4/e927e0653ba63b02a4ca5b4d852a8d1d678afbf69b3dbf9c4d0785ac905c/pynacl-1.6.2-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", upload-time = 2026-01-01T17:32:18Z, size = 800020, hashes = { sha256 = "8845c0631c0be43abdd865511c41eab235e0be69c81dc66a50911594198679b0" } }, { url = "https://files.pythonhosted.org/packages/7f/81/d60984052df5c97b1d24365bc1e30024379b42c4edcd79d2436b1b9806f2/pynacl-1.6.2-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", upload-time = 2026-01-01T17:32:20Z, size = 1399174, hashes = { sha256 = "22de65bb9010a725b0dac248f353bb072969c94fa8d6b1f34b87d7953cf7bbe4" } }, { url = "https://files.pythonhosted.org/packages/68/f7/322f2f9915c4ef27d140101dd0ed26b479f7e6f5f183590fd32dfc48c4d3/pynacl-1.6.2-cp38-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", upload-time = 2026-01-01T17:32:22Z, size = 835085, hashes = { sha256 = "46065496ab748469cdd999246d17e301b2c24ae2fdf739132e580a0e94c94a87" } }, { url = "https://files.pythonhosted.org/packages/3e/d0/f301f83ac8dbe53442c5a43f6a39016f94f754d7a9815a875b65e218a307/pynacl-1.6.2-cp38-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", upload-time = 2026-01-01T17:32:23Z, size = 1437614, hashes = { sha256 = "8a66d6fb6ae7661c58995f9c6435bda2b1e68b54b598a6a10247bfcdadac996c" } }, { url = "https://files.pythonhosted.org/packages/c4/58/fc6e649762b029315325ace1a8c6be66125e42f67416d3dbd47b69563d61/pynacl-1.6.2-cp38-abi3-manylinux_2_34_aarch64.whl", upload-time = 2026-01-01T17:32:25Z, size = 818251, hashes = { sha256 = "26bfcd00dcf2cf160f122186af731ae30ab120c18e8375684ec2670dccd28130" } }, { url = "https://files.pythonhosted.org/packages/c9/a8/b917096b1accc9acd878819a49d3d84875731a41eb665f6ebc826b1af99e/pynacl-1.6.2-cp38-abi3-manylinux_2_34_x86_64.whl", upload-time = 2026-01-01T17:32:27Z, size = 1402859, hashes = { sha256 = "c8a231e36ec2cab018c4ad4358c386e36eede0319a0c41fed24f840b1dac59f6" } }, { url = "https://files.pythonhosted.org/packages/85/42/fe60b5f4473e12c72f977548e4028156f4d340b884c635ec6b063fe7e9a5/pynacl-1.6.2-cp38-abi3-musllinux_1_2_aarch64.whl", upload-time = 2026-01-01T17:32:29Z, size = 791926, hashes = { sha256 = "68be3a09455743ff9505491220b64440ced8973fe930f270c8e07ccfa25b1f9e" } }, { url = "https://files.pythonhosted.org/packages/fa/f9/e40e318c604259301cc091a2a63f237d9e7b424c4851cafaea4ea7c4834e/pynacl-1.6.2-cp38-abi3-musllinux_1_2_x86_64.whl", upload-time = 2026-01-01T17:32:31Z, size = 1363101, hashes = { sha256 = "8b097553b380236d51ed11356c953bf8ce36a29a3e596e934ecabe76c985a577" } }, { url = "https://files.pythonhosted.org/packages/48/47/e761c254f410c023a469284a9bc210933e18588ca87706ae93002c05114c/pynacl-1.6.2-cp38-abi3-win32.whl", upload-time = 2026-01-01T17:32:33Z, size = 227421, hashes = { sha256 = "5811c72b473b2f38f7e2a3dc4f8642e3a3e9b5e7317266e4ced1fba85cae41aa" } }, { url = "https://files.pythonhosted.org/packages/41/ad/334600e8cacc7d86587fe5f565480fde569dfb487389c8e1be56ac21d8ac/pynacl-1.6.2-cp38-abi3-win_amd64.whl", upload-time = 2026-01-01T17:32:34Z, size = 239754, hashes = { sha256 = "62985f233210dee6548c223301b6c25440852e13d59a8b81490203c3227c5ba0" } }, { url = "https://files.pythonhosted.org/packages/29/7d/5945b5af29534641820d3bd7b00962abbbdfee84ec7e19f0d5b3175f9a31/pynacl-1.6.2-cp38-abi3-win_arm64.whl", upload-time = 2026-01-01T17:32:36Z, size = 184801, hashes = { sha256 = "834a43af110f743a754448463e8fd61259cd4ab5bbedcf70f9dabad1d28a394c" } }, ] [[packages]] name = "python-dotenv" version = "1.2.2" sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", upload-time = 2026-03-01T16:00:26Z, size = 50135, hashes = { sha256 = "2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3" } } wheels = [{ url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", upload-time = 2026-03-01T16:00:25Z, size = 22101, hashes = { sha256 = "1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a" } }] [[packages]] name = "pyyaml" version = "6.0.3" sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", upload-time = 2025-09-25T21:33:16Z, size = 130960, hashes = { sha256 = "d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f" } } wheels = [ { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", upload-time = 2025-09-25T21:32:23Z, size = 181669, hashes = { sha256 = "8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8" } }, { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", upload-time = 2025-09-25T21:32:25Z, size = 173252, hashes = { sha256 = "2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1" } }, { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", upload-time = 2025-09-25T21:32:26Z, size = 767081, hashes = { sha256 = "ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c" } }, { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", upload-time = 2025-09-25T21:32:27Z, size = 841159, hashes = { sha256 = "a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5" } }, { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", upload-time = 2025-09-25T21:32:28Z, size = 801626, hashes = { sha256 = "0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6" } }, { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", upload-time = 2025-09-25T21:32:30Z, size = 753613, hashes = { sha256 = "f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6" } }, { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", upload-time = 2025-09-25T21:32:31Z, size = 794115, hashes = { sha256 = "eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be" } }, { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", upload-time = 2025-09-25T21:32:32Z, size = 137427, hashes = { sha256 = "d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26" } }, { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", upload-time = 2025-09-25T21:32:33Z, size = 154090, hashes = { sha256 = "79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c" } }, { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", upload-time = 2025-09-25T21:32:34Z, size = 140246, hashes = { sha256 = "5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb" } }, { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", upload-time = 2025-09-25T21:32:35Z, size = 181814, hashes = { sha256 = "8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac" } }, { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", upload-time = 2025-09-25T21:32:36Z, size = 173809, hashes = { sha256 = "34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310" } }, { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", upload-time = 2025-09-25T21:32:37Z, size = 766454, hashes = { sha256 = "501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7" } }, { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", upload-time = 2025-09-25T21:32:39Z, size = 836355, hashes = { sha256 = "b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788" } }, { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", upload-time = 2025-09-25T21:32:40Z, size = 794175, hashes = { sha256 = "c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5" } }, { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", upload-time = 2025-09-25T21:32:42Z, size = 755228, hashes = { sha256 = "7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764" } }, { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", upload-time = 2025-09-25T21:32:43Z, size = 789194, hashes = { sha256 = "5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35" } }, { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", upload-time = 2025-09-25T21:32:57Z, size = 156429, hashes = { sha256 = "4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac" } }, { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", upload-time = 2025-09-25T21:32:59Z, size = 143912, hashes = { sha256 = "93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3" } }, { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", upload-time = 2025-09-25T21:32:44Z, size = 189108, hashes = { sha256 = "02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3" } }, { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", upload-time = 2025-09-25T21:32:45Z, size = 183641, hashes = { sha256 = "c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba" } }, { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", upload-time = 2025-09-25T21:32:48Z, size = 831901, hashes = { sha256 = "6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c" } }, { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", upload-time = 2025-09-25T21:32:50Z, size = 861132, hashes = { sha256 = "a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702" } }, { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", upload-time = 2025-09-25T21:32:51Z, size = 839261, hashes = { sha256 = "00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c" } }, { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", upload-time = 2025-09-25T21:32:52Z, size = 805272, hashes = { sha256 = "66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065" } }, { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", upload-time = 2025-09-25T21:32:54Z, size = 829923, hashes = { sha256 = "16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65" } }, { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", upload-time = 2025-09-25T21:32:55Z, size = 174062, hashes = { sha256 = "4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9" } }, { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", upload-time = 2025-09-25T21:32:56Z, size = 149341, hashes = { sha256 = "ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b" } }, ] [[packages]] name = "requests" version = "2.33.1" sdist = { url = "https://files.pythonhosted.org/packages/5f/a4/98b9c7c6428a668bf7e42ebb7c79d576a1c3c1e3ae2d47e674b468388871/requests-2.33.1.tar.gz", upload-time = 2026-03-30T16:09:15Z, size = 134120, hashes = { sha256 = "18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517" } } wheels = [{ url = "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl", upload-time = 2026-03-30T16:09:13Z, size = 64947, hashes = { sha256 = "4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a" } }] [[packages]] name = "typing-extensions" version = "4.15.0" sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", upload-time = 2025-08-25T13:49:26Z, size = 109391, hashes = { sha256 = "0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466" } } wheels = [{ url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", upload-time = 2025-08-25T13:49:24Z, size = 44614, hashes = { sha256 = "f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548" } }] [[packages]] name = "typing-inspection" version = "0.4.2" sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", upload-time = 2025-10-01T02:14:41Z, size = 75949, hashes = { sha256 = "ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464" } } wheels = [{ url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", upload-time = 2025-10-01T02:14:40Z, size = 14611, hashes = { sha256 = "4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7" } }] [[packages]] name = "urllib3" version = "2.6.3" sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", upload-time = 2026-01-07T16:24:43Z, size = 435556, hashes = { sha256 = "1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed" } } wheels = [{ url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", upload-time = 2026-01-07T16:24:42Z, size = 131584, hashes = { sha256 = "bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4" } }] pydantic-pydantic-ba0aa01/.github/actions/people/requirements.in000066400000000000000000000000531517143232300251430ustar00rootroot00000000000000pydantic pydantic-settings PyGithub pyyaml pydantic-pydantic-ba0aa01/.github/dependabot.yml000066400000000000000000000007371517143232300220050ustar00rootroot00000000000000version: 2 updates: - package-ecosystem: github-actions directory: / schedule: interval: monthly cooldown: default-days: 7 - package-ecosystem: cargo directory: /pydantic-core/ schedule: interval: monthly groups: rust-deps: patterns: - '*' # pyo3 updates will require jiter updates, we'll handle them manually anyway exclude-patterns: - 'pyo3*' cooldown: default-days: 7 pydantic-pydantic-ba0aa01/.github/release.yml000066400000000000000000000006361517143232300213160ustar00rootroot00000000000000changelog: exclude: labels: - relnotes-ignore - documentation categories: - title: Packaging labels: - relnotes-packaging - title: New Features labels: - relnotes-feature - title: Changes labels: - relnotes-change - title: Performance labels: - relnotes-performance - title: Fixes labels: - relnotes-fix pydantic-pydantic-ba0aa01/.github/workflows/000077500000000000000000000000001517143232300212035ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/.github/workflows/ci.yml000066400000000000000000001123351517143232300223260ustar00rootroot00000000000000name: CI on: push: branches: - main tags: - '**' pull_request: {} env: COLUMNS: 150 UV_FROZEN: true FORCE_COLOR: 1 permissions: contents: read jobs: lint: runs-on: ubuntu-latest name: Lint ${{ matrix.python-version }} strategy: fail-fast: false matrix: python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: python-version: ${{ matrix.python-version }} enable-cache: true # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions - name: Install dependencies # Installing pip is required for the pre-commit action: run: | uv sync --all-packages --group linting --all-extras uv pip install pip - uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 with: extra_args: --all-files --verbose env: SKIP: no-commit-to-branch UV_NO_PROGRESS: '1' core-build-sdist: runs-on: ubuntu-latest name: core / Build sdist steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: '3.13' - uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad # v1.50.1 with: working-directory: pydantic-core command: sdist args: --out dist rust-toolchain: stable - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: pydantic_core_pypi_files_sdist path: pydantic-core/dist core-build: name: core / Build on ${{ matrix.os }} (${{ matrix.target }} - ${{ matrix.interpreter || 'all' }}${{ matrix.os == 'linux' && format(' - {0}', matrix.manylinux == 'auto' && 'manylinux' || matrix.manylinux) || '' }}) # only run on push to main, if a full build was requested or on release: if: startsWith(github.ref, 'refs/tags/') || github.ref == 'refs/heads/main' || contains(github.event.pull_request.labels.*.name, 'full build') strategy: fail-fast: false matrix: os: [linux, macos, windows] target: [undefined] manylinux: [auto] include: # manylinux for various platforms # x86_64 and aarch64 are PGO optimized below - os: linux manylinux: auto target: i686 - os: linux manylinux: auto target: armv7 interpreter: 3.9 3.10 3.11 3.12 3.13 3.14 3.14t - os: linux manylinux: auto target: ppc64le interpreter: 3.9 3.10 3.11 3.12 3.13 3.14 3.14t - os: linux manylinux: auto target: riscv64gc-unknown-linux-gnu interpreter: 3.9 3.10 3.11 3.12 3.13 3.14 3.14t - os: linux manylinux: auto target: s390x interpreter: 3.9 3.10 3.11 3.12 3.13 3.14 3.14t # manylinux pypy and graalpy on major architectures: - os: linux manylinux: auto target: x86_64 interpreter: pypy3.11 graalpy3.11 graalpy3.12 - os: linux manylinux: auto target: aarch64 interpreter: graalpy3.11 graalpy3.12 # musllinux - os: linux manylinux: musllinux_1_1 target: x86_64 - os: linux manylinux: musllinux_1_1 target: aarch64 - os: linux manylinux: musllinux_1_1 target: armv7 # macos; # all versions x86_64 # arm pypy and older pythons which can't be run on the arm hardware for PGO - os: macos target: x86_64 interpreter: 3.9 3.10 3.11 3.12 3.13 3.14 3.14t pypy3.11 graalpy3.11 graalpy3.12 - os: macos target: aarch64 interpreter: 3.9 pypy3.11 graalpy3.11 graalpy3.12 # windows; # x86_64 pypy builds are not PGO optimized # i686 not supported by pypy # windows 11 arm supports 3.11 and up, not PGO optimized for now - os: windows target: x86_64 interpreter: pypy3.11 - os: windows target: i686 python-architecture: x86 interpreter: 3.9 3.10 3.11 3.12 3.13 3.14 3.14t - os: windows target: aarch64 runs-on: windows-11-arm interpreter: 3.11 3.12 3.13 3.14 3.14t exclude: # was just a dummy variable to set a default value for target - target: undefined runs-on: ${{ matrix.runs-on || format('{0}-latest', (matrix.os == 'linux' && 'ubuntu') || matrix.os) }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: '3.13' architecture: ${{ matrix.python-architecture || 'x64' }} - run: pip install -U twine 'ruff==0.5.0' typing_extensions - name: Build wheels uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad # v1.50.1 with: working-directory: pydantic-core target: ${{ matrix.target }} manylinux: ${{ matrix.manylinux }} args: --release --out dist --interpreter ${{ matrix.interpreter || '3.9 3.10 3.11 3.12 3.13 3.14 3.14t pypy3.11' }} rust-toolchain: stable docker-options: -e CI - run: ${{ (matrix.os == 'windows' && 'dir') || 'ls -lh' }} dist/ working-directory: pydantic-core - run: twine check --strict dist/* working-directory: pydantic-core - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: pydantic_core_pypi_files_${{ matrix.os }}_${{ matrix.target }}_${{ matrix.interpreter || 'all' }}_${{ matrix.manylinux }} path: pydantic-core/dist core-build-pgo: name: core / Build PGO-optimized on ${{ matrix.platform.os }} / ${{ matrix.interpreter }} # only run on push to main, if a full build was requested or on release: if: startsWith(github.ref, 'refs/tags/') || github.ref == 'refs/heads/main' || contains(github.event.pull_request.labels.*.name, 'full build') strategy: fail-fast: false matrix: platform: - os: linux runs-on: ubuntu-latest - os: linux_aarch64 runs-on: ubuntu-24.04-arm - os: windows runs-on: windows-latest - os: macos runs-on: macos-latest interpreter: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14', '3.14t'] exclude: # macos arm only supported from 3.10 and up - platform: os: macos interpreter: '3.9' runs-on: ${{ matrix.platform.runs-on }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: python-version: ${{ matrix.interpreter }} enable-cache: false - name: Install rust stable id: rust-toolchain # no release versioning, see https://github.com/dtolnay/rust-toolchain/issues/180 uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 with: components: llvm-tools toolchain: stable - name: Build PGO wheel id: pgo-wheel uses: ./.github/actions/core-build-pgo-wheel with: working-directory: pydantic-core interpreter: ${{ matrix.interpreter }} rust-toolchain: ${{ steps.rust-toolchain.outputs.name }} - run: ${{ (startsWith(matrix.platform.os, 'windows') && 'dir') || 'ls -lh' }} dist/ working-directory: pydantic-core - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: pydantic_core_pypi_files_${{ matrix.platform.os }}_${{ matrix.interpreter }} path: pydantic-core/dist core-build-wasm-emscripten: name: core / Build WASM Emscripten runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - name: Install rust nightly # no release versioning, see https://github.com/dtolnay/rust-toolchain/issues/180 uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 with: components: rust-src targets: wasm32-unknown-emscripten toolchain: nightly - name: Cache rust uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: lookup-only: true - uses: mymindstorm/setup-emsdk@6ab9eb1bda2574c4ddb79809fc9247783eaf9021 # v14 with: # NOTE!: as per https://github.com/pydantic/pydantic-core/pull/149 this version needs to match the version # in pydantic-core/node_modules/pyodide/pyodide-lock.json, to get the version, run: # `cat pydantic-core/node_modules/pyodide/pyodide-lock.json | jq .info.platform` version: '4.0.9' actions-cache-folder: emsdk-cache - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: python-version: '3.13' enable-cache: false - name: Install dependencies run: uv sync --all-packages --group testing-extra --group wasm --all-extras - name: Build wheels run: make -C pydantic-core build-wasm - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: node-version: '18' package-manager-cache: false - run: npm install working-directory: pydantic-core - run: npm run test working-directory: pydantic-core - run: | ls -lh dist/ working-directory: pydantic-core - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: pydantic_core_wasm_wheels path: pydantic-core/dist core-bench: name: core / Run Rust benchmarks runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - name: Install rust nightly # no release versioning, see https://github.com/dtolnay/rust-toolchain/issues/180 uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 with: toolchain: nightly - name: Cache rust uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: lookup-only: false # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: '3.13' - run: pip install typing_extensions - run: cargo bench working-directory: pydantic-core core-test-builds-arch: name: core / Test build on ${{ matrix.target }}-${{ matrix.distro }} needs: [core-build] runs-on: ubuntu-latest strategy: fail-fast: false matrix: target: [armv7, s390x, ppc64le] distro: ['ubuntu22.04'] include: - target: aarch64 distro: alpine_latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - name: Get dist artifacts uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: pattern: pydantic_core_pypi_files_linux_* merge-multiple: true path: dist - uses: uraimo/run-on-arch-action@d94c13912ea685de38fccc1109385b83fd79427d # v3.0.1 name: Install and test with: arch: ${{ matrix.target }} distro: ${{ matrix.distro }} githubToken: ${{ github.token }} install: | set -x if command -v apt-get &> /dev/null; then echo "installing python & pip with apt-get..." apt-get update apt-get install -y --no-install-recommends python3 python3-pip python3-venv git curl else echo "installing python & pip with apk..." apk update apk add python3 py3-pip git curl fi env: | UV_NO_PROGRESS: '1' # Until we move all dev dependencies to the main `pydantic` package, use this workaround: # Sync the pydantic-core workspace to get the dev dependencies (without the actual `pydantic-core` package), # and then sync the parent workspace: run: | set -x curl -LsSf https://astral.sh/uv/install.sh | sh source $HOME/.local/bin/env uv sync --directory pydantic-core --group testing-extra --no-install-package pydantic-core uv sync --group testing-extra --no-install-package pydantic-core --no-install-package pytest-memray --no-install-package memray --no-install-package pytest-codspeed --no-install-package cffi --inexact uv pip install pydantic-core --no-index --no-deps --find-links dist --force-reinstall uv run --no-sync pytest tests/pydantic_core --ignore=tests/pydantic_core/test_docstrings.py uv run --no-sync python -c 'import pydantic_core._pydantic_core; print(pydantic_core._pydantic_core.__version__)' uv run --no-sync python -c 'from pydantic_core._pydantic_core import build_info; print(f"{build_info=}")' core-test-builds-os: name: core / Test build on ${{ matrix.platform.os }} needs: [core-build, core-build-pgo] strategy: fail-fast: false matrix: platform: - runs-on: ubuntu-latest os: linux - runs-on: ubuntu-24.04-arm os: linuw_aarch64 - runs-on: windows-latest os: windows - runs-on: windows-11-arm os: windows_aarch64 - runs-on: macos-latest os: macos runs-on: ${{ matrix.platform.runs-on }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - name: install uv uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: enable-cache: true # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions - name: get dist artifacts uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: pattern: pydantic_core_pypi_files_* merge-multiple: true path: dist # Until we move all dev dependencies to the main `pydantic` package, use this workaround: # Sync the pydantic-core workspace to get the dev dependencies (without the actual `pydantic-core` package), # and then sync the parent workspace: - run: | uv sync --directory pydantic-core --group testing-extra --no-install-package pydantic-core uv sync --group testing-extra --no-install-package pydantic-core --inexact uv pip install pydantic-core --no-index --no-deps --find-links dist --force-reinstall uv run --no-sync pytest tests/pydantic_core --ignore=tests/pydantic_core/test_docstrings.py uv run --no-sync python -c 'import pydantic_core._pydantic_core; print(pydantic_core._pydantic_core.__version__)' uv run --no-sync python -c 'from pydantic_core._pydantic_core import build_info; print(f"{build_info=}")' core-test-os: name: core / Test on ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu, macos, windows] runs-on: ${{ matrix.os }}-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - name: Install rust stable # no release versioning, see https://github.com/dtolnay/rust-toolchain/issues/180 uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 with: toolchain: stable - name: Cache rust uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: lookup-only: false # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: enable-cache: true # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions - name: Install dependencies run: uv sync --all-packages --group testing-extra env: RUST_BACKTRACE: 1 - run: uv pip freeze - run: uv run pytest tests/pydantic_core - run: cargo test working-directory: pydantic-core core-test-msrv: name: core / Test MSRV runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: enable-cache: true # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions - name: Resolve MSRV id: resolve-msrv run: echo MSRV=`cargo metadata --format-version 1 --no-deps --frozen --quiet --offline --manifest-path pydantic-core/Cargo.toml | jq -r '.packages[0].rust_version'` >> $GITHUB_OUTPUT - name: Install rust MSRV # no release versioning, see https://github.com/dtolnay/rust-toolchain/issues/180 uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 with: toolchain: ${{ steps.resolve-msrv.outputs.MSRV }} - name: Cache rust uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: lookup-only: false # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions - name: Install dependencies run: uv sync --all-packages --all-extras --group testing-extra env: RUST_BACKTRACE: 1 - run: uv pip freeze - run: uv run pytest tests/pydantic_core - run: cargo test working-directory: pydantic-core # test with a debug build as it picks up errors which optimised release builds do not core-test-debug: name: core / Test with debug build (${{ matrix.python-version }}) runs-on: ubuntu-latest strategy: fail-fast: false matrix: python-version: - '3.13' # Segmentation fault on pypy3.11.15 (latest), see https://github.com/pypy/pypy/issues/5400 - 'pypy3.11.13' steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: python-version: ${{ matrix.python-version }} enable-cache: true # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions - name: Install rust stable # no release versioning, see https://github.com/dtolnay/rust-toolchain/issues/180 uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 with: toolchain: stable - name: Cache rust uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: lookup-only: false # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions - name: Install dependencies run: uv sync --all-packages --all-extras --group testing-extra - run: uv run --no-sync maturin develop --uv working-directory: pydantic-core - run: uv pip freeze - run: uv run pytest build-pydantic: runs-on: ubuntu-latest if: startsWith(github.ref, 'refs/tags/') outputs: pydantic-version: ${{ steps.check-tag.outputs.VERSION }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: enable-cache: false - run: uv sync --only-group build - name: Check pydantic version id: check-tag uses: samuelcolvin/check-python-version@ee87cddb8049d2694cc03badc8569765a05cef00 # v5 with: version_file_path: pydantic/version.py - name: Build pydantic library run: uv run --no-sync python -m build --installer uv - run: ls -lh dist/ - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: pydantic_pypi_files path: dist docs-build: runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: python-version: '3.12' enable-cache: true # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions - name: Install dependencies # Unlike the docs build, we don't use mkdocs_material-insiders # Because the secret for accessing the library is not accessible from forks, but we still want to run # this job on public CI runs. run: uv sync --all-packages --group docs - run: uv run python -c 'import docs.plugins.main' # Taken from docs-build.sh - name: prepare shortcuts for extra modules run: | ln -s pydantic-core/python/pydantic_core pydantic_core ln -s .venv/lib/python*/site-packages/pydantic_settings pydantic_settings ln -s .venv/lib/python*/site-packages/pydantic_extra_types pydantic_extra_types - run: PYTHONPATH="$PWD${PYTHONPATH:+:${PYTHONPATH}}" uv run mkdocs build test-memray: name: Test memray runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: python-version: '3.12' enable-cache: true # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions - name: install deps run: uv sync --all-packages --group testing-extra - name: Run tests run: uv run pytest --ignore=tests/mypy/ --ignore=tests/test_docs.py --memray test: name: Test ${{ matrix.os }} / ${{ matrix.python-version }} strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] # Segmentation fault on pypy3.11.15 (latest), see https://github.com/pypy/pypy/issues/5400 python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14', '3.14t', 'pypy3.11.13'] include: # test macos intel just with latest python version - os: macos-15-intel python-version: '3.14' - os: macos-15-intel python-version: '3.14t' env: OS: ${{ matrix.os }} DEPS: yes UV_PYTHON_PREFERENCE: only-managed runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: python-version: ${{ matrix.python-version }} enable-cache: true # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions - name: Install dependencies run: uv sync --all-packages --group testing-extra --all-extras - run: 'uv run python -c "import pydantic.version; print(pydantic.version.version_info())"' - run: mkdir coverage - name: Run pytest run: make test NUM_THREADS=${{ endsWith(matrix.python-version, 't') && '4' || '1' }} env: COVERAGE_FILE: coverage/.coverage.${{ runner.os }}-py${{ matrix.python-version }} CONTEXT: ${{ runner.os }}-py${{ matrix.python-version }}-without-deps - name: Store coverage files uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: coverage-${{ matrix.os }}-${{ matrix.python-version }} path: coverage include-hidden-files: true test-plugin: name: Test Pydantic plugin runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: python-version: '3.12' enable-cache: true # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions - name: Install dependencies run: uv sync - name: Install example plugin run: uv pip install ./tests/plugin - run: uv run pytest tests/plugin env: TEST_PLUGIN: 1 test-mypy: name: Mypy typechecking tests runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: python-version: '3.13' enable-cache: true # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions - name: Install dependencies run: uv sync --group typechecking --all-extras - run: mkdir coverage - name: Run mypy tests run: uv run coverage run -m pytest tests/mypy --test-mypy env: COVERAGE_FILE: coverage/.coverage.linux-mypy CONTEXT: linux-mypy - name: Store coverage files uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: coverage-mypy path: coverage include-hidden-files: true test-typechecking-integration: name: Typechecking integration tests runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: python-version: '3.12' enable-cache: true # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions - name: Install dependencies run: uv sync --group typechecking - name: Run typechecking integration tests (Pyright) run: make test-typechecking-pyright - name: Run typechecking integration tests (Mypy) run: make test-typechecking-mypy - name: Run typechecking integration tests (Pyrefly) run: make test-typechecking-pyrefly coverage-combine: needs: [test, test-mypy] runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: '3.12' - name: Get coverage files uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: merge-multiple: true pattern: coverage-* path: coverage - run: pip install coverage[toml] - run: ls -la coverage - run: coverage combine coverage - run: coverage report - run: coverage html --show-contexts --title "pydantic coverage for ${{ github.sha }}" - name: Store coverage data uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: coverage-data path: .coverage include-hidden-files: true - name: Store coverage HTML uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: coverage-html path: htmlcov coverage-pr-comment: needs: coverage-combine runs-on: ubuntu-latest if: github.event_name == 'pull_request' permissions: pull-requests: write contents: write steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - name: Download coverage data uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: coverage-data - name: Generate coverage comment id: coverage-comment uses: py-cov-action/python-coverage-comment-action@7188638f871f721a365d644f505d1ff3df20d683 # v3.40 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Store coverage comment uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 if: steps.coverage-comment.outputs.COMMENT_FILE_WRITTEN == 'true' with: name: python-coverage-comment-action path: python-coverage-comment-action.txt test-typing-extensions: name: Test typing-extensions (`main` branch) on Python ${{ matrix.python-version }} runs-on: ubuntu-latest strategy: fail-fast: false matrix: python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: python-version: ${{ matrix.python-version }} enable-cache: true # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions - name: Install dependencies run: uv sync --all-packages --group testing-extra --all-extras - name: Install typing-extensions run: uv pip install 'typing-extensions @ git+https://github.com/python/typing_extensions.git' - name: Run tests run: make test # https://github.com/marketplace/actions/alls-green check: # This job does nothing and is only used for the branch protection if: always() outputs: result: ${{ steps.all-green.outputs.result }} needs: [lint, docs-build, test, test-memray, test-mypy, test-plugin, core-test-os, core-test-debug, core-build-wasm-emscripten] runs-on: ubuntu-latest steps: - name: Decide whether the needed jobs succeeded or failed uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2 id: all-green with: jobs: ${{ toJSON(needs) }} release-pydantic-core: needs: [core-test-builds-arch, core-test-builds-os, core-build-sdist, check] if: needs.check.outputs.result == 'success' && startsWith(github.ref, 'refs/tags/') runs-on: ubuntu-latest environment: release permissions: id-token: write steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: enable-cache: false - run: uv sync --only-group build - name: Extract pydantic-core version id: core-version run: | VERSION=$(cargo metadata --format-version 1 --no-deps --frozen --quiet --offline --manifest-path pydantic-core/Cargo.toml | jq -r '.packages[0].version') echo "VERSION=$VERSION" >> "$GITHUB_OUTPUT" echo "pydantic-core version: $VERSION" - name: Check if pydantic-core version is already on PyPI id: check-pypi run: | STATUS=$(curl -s -o /dev/null -I -w "%{http_code}" https://pypi.org/pypi/pydantic-core/${STEPS_CORE_VERSION_OUTPUTS_VERSION}/json) if [ "$STATUS" = "200" ]; then echo "already_published=true" >> "$GITHUB_OUTPUT" echo "pydantic-core ${STEPS_CORE_VERSION_OUTPUTS_VERSION} is already on PyPI, skipping publish" else echo "already_published=false" >> "$GITHUB_OUTPUT" echo "pydantic-core ${STEPS_CORE_VERSION_OUTPUTS_VERSION} not found on PyPI, will publish" fi env: STEPS_CORE_VERSION_OUTPUTS_VERSION: ${{ steps.core-version.outputs.VERSION }} - name: Get pydantic-core dist artifacts if: steps.check-pypi.outputs.already_published != 'true' uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: pattern: pydantic_core_pypi_files_* merge-multiple: true path: pydantic-core-dist - name: Test pydantic-core wheels integrity if: steps.check-pypi.outputs.already_published != 'true' run: | for whl in pydantic-core-dist/*.whl; do unzip -qt "$whl"; done uv run --no-sync twine check --strict pydantic-core-dist/* - name: Publish pydantic-core to PyPI if: steps.check-pypi.outputs.already_published != 'true' run: uv publish --trusted-publishing always pydantic-core-dist/* release-pydantic: needs: [build-pydantic, release-pydantic-core] if: startsWith(github.ref, 'refs/tags/') runs-on: ubuntu-latest environment: release permissions: id-token: write contents: write steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: enable-cache: false - run: uv sync --only-group build - name: Get pydantic dist artifacts uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: pydantic_pypi_files path: pydantic-dist - name: Test pydantic artifacts integrity run: | for whl in pydantic-dist/*.whl; do unzip -qt "$whl"; done uv run --no-sync twine check --strict pydantic-dist/* - name: Upload package to PyPI uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0 with: packages-dir: pydantic-dist/ send-tweet: name: Send tweet needs: [build-pydantic, release-pydantic] if: needs.release-pydantic.result == 'success' runs-on: ubuntu-latest steps: - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: '3.12' - name: Install dependencies run: pip install tweepy==4.14.0 - name: Send tweet shell: python run: | import os import tweepy client = tweepy.Client( access_token=os.getenv("TWITTER_ACCESS_TOKEN"), access_token_secret=os.getenv("TWITTER_ACCESS_TOKEN_SECRET"), consumer_key=os.getenv("TWITTER_CONSUMER_KEY"), consumer_secret=os.getenv("TWITTER_CONSUMER_SECRET"), ) version = os.getenv("VERSION").strip('"') if "b" in version: official_version = version[:version.index("b")] tweet = os.getenv("BETA_TWEET").format(version=version, official_version=official_version) else: tweet = os.getenv("TWEET").format(version=version) client.create_tweet(text=tweet) env: VERSION: ${{ needs.build-pydantic.outputs.pydantic-version }} TWEET: | Pydantic version {version} is out! 🎉 https://github.com/pydantic/pydantic/releases/tag/v{version} BETA_TWEET: | Pydantic beta version {version} is out! 🚀 Please try v{version} in the next week before we release v{official_version}, and let us know if you encounter any issues! https://github.com/pydantic/pydantic/releases/tag/v{version} TWITTER_CONSUMER_KEY: ${{ secrets.TWITTER_CONSUMER_KEY }} TWITTER_CONSUMER_SECRET: ${{ secrets.TWITTER_CONSUMER_SECRET }} TWITTER_ACCESS_TOKEN: ${{ secrets.TWITTER_ACCESS_TOKEN }} TWITTER_ACCESS_TOKEN_SECRET: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }} pydantic-pydantic-ba0aa01/.github/workflows/codspeed.yml000066400000000000000000000035631517143232300235230ustar00rootroot00000000000000name: codspeed on: push: branches: - main pull_request: # `workflow_dispatch` allows CodSpeed to trigger backtest # performance analysis in order to generate initial data. workflow_dispatch: env: UV_FROZEN: true UV_PYTHON: 3.14 permissions: contents: read jobs: codspeed-profiling: name: CodSpeed profiling runs-on: ubuntu-24.04 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 # Using this action is still necessary for CodSpeed to work: - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: ${{ env.UV_PYTHON }} - name: install deps run: uv sync --all-packages --group testing-extra --extra email --frozen - name: install rust stable # no release versioning, see https://github.com/dtolnay/rust-toolchain/issues/180 uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 with: components: llvm-tools toolchain: stable - name: cache rust uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: workspaces: pydantic-core - name: install pydantic-core with profiling symbols run: | cd pydantic-core uv pip uninstall pytest-speed make build-pgo env: CARGO_PROFILE_RELEASE_DEBUG: 'line-tables-only' CARGO_PROFILE_RELEASE_STRIP: 'false' - name: Run CodSpeed benchmarks uses: CodSpeedHQ/action@1c8ae4843586d3ba879736b7f6b7b0c990757fab # v4.12.1 with: mode: simulation run: uv run --no-sync pytest ./tests/benchmarks ./tests/pydantic_core/benchmarks --codspeed pydantic-pydantic-ba0aa01/.github/workflows/coverage.yml000066400000000000000000000016471517143232300235310ustar00rootroot00000000000000name: Post coverage comment on: # zizmor: ignore[dangerous-triggers] -- workflow_run is used safely here; no code checkout occurs workflow_run: workflows: ['CI'] types: - completed jobs: post-coverage-comment: name: Push coverage comment runs-on: ubuntu-latest if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' permissions: pull-requests: write contents: write actions: read steps: # DO NOT run actions/checkout here, for security reasons # For details, refer to https://securitylab.github.com/research/github-actions-preventing-pwn-requests/ - name: Post comment uses: py-cov-action/python-coverage-comment-action@7188638f871f721a365d644f505d1ff3df20d683 # v3.40 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_PR_RUN_ID: ${{ github.event.workflow_run.id }} pydantic-pydantic-ba0aa01/.github/workflows/dependencies-check.yml000066400000000000000000000032371517143232300254340ustar00rootroot00000000000000name: Dependencies Check on: schedule: - cron: '43 3 * * 6,3' workflow_dispatch: {} env: UV_FROZEN: true permissions: contents: read jobs: find_dependency_cases: runs-on: ubuntu-latest outputs: PYTHON_DEPENDENCY_CASES: ${{ steps.list-python-dependencies.outputs.PYTHON_DEPENDENCY_CASES }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false # no release versioning, see https://github.com/samuelcolvin/list-python-dependencies/issues/2 - uses: samuelcolvin/list-python-dependencies@43f660fbd655f25c3e3ebd3165b09974bbf98e05 id: list-python-dependencies with: mode: first-last test: name: Test py${{ matrix.python-version }} on ${{ matrix.PYTHON_DEPENDENCY_CASE }} needs: - find_dependency_cases strategy: fail-fast: true matrix: python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] PYTHON_DEPENDENCY_CASE: ${{ fromJSON(needs.find_dependency_cases.outputs.PYTHON_DEPENDENCY_CASES) }} runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: ${{ matrix.python-version }} - run: pip install uv - run: uv sync --all-extras - run: uv pip install ${MATRIX_PYTHON_DEPENDENCY_CASE} env: MATRIX_PYTHON_DEPENDENCY_CASE: ${{ matrix.PYTHON_DEPENDENCY_CASE }} - run: uv pip freeze - run: make test pydantic-pydantic-ba0aa01/.github/workflows/docs-update.yml000066400000000000000000000106641517143232300241450ustar00rootroot00000000000000name: Publish Documentation on: push: branches: - main - docs-update tags: - '**' concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true env: COLUMNS: 150 UV_FROZEN: true permissions: contents: read jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: python-version: '3.13' enable-cache: true # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions - name: Install dependencies # Installing pip is required for the pre-commit action: run: | uv sync --all-packages --group linting --all-extras uv pip install pip - uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 with: extra_args: --all-files --verbose env: SKIP: no-commit-to-branch UV_NO_PROGRESS: '1' test: runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: python-version: '3.13' enable-cache: true # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions - name: Install dependencies run: uv sync --all-packages --group testing-extra --all-extras - run: 'uv run python -c "import pydantic.version; print(pydantic.version.version_info())"' - run: make test publish: # Compare with the docs-build job in .github/workflows/ci.yml needs: [lint, test] runs-on: ubuntu-latest timeout-minutes: 30 permissions: contents: write steps: - name: Checkout docs-site uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: docs-site persist-credentials: true - name: Checkout current branch uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: true - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: python-version: '3.13' enable-cache: false - run: uv sync --all-packages --group docs --group docs-upload - run: uv pip install --default-index https://pydantic:${PPPR_TOKEN}@pppr.pydantic.dev/simple/ mkdocs-material env: PPPR_TOKEN: ${{ secrets.PPPR_TOKEN }} - run: uv run python -c 'import docs.plugins.main' # Taken from docs-build.sh - name: Prepare shortcuts for extra modules run: | ln -s pydantic-core/python/pydantic_core pydantic_core ln -s .venv/lib/python*/site-packages/pydantic_settings pydantic_settings ln -s .venv/lib/python*/site-packages/pydantic_extra_types pydantic_extra_types - name: Set git credentials run: | git config --global user.name "${GITHUB_ACTOR}" git config --global user.email "${GITHUB_ACTOR}@users.noreply.github.com" - run: PYTHONPATH="$PWD${PYTHONPATH:+:${PYTHONPATH}}" uv run mike deploy -b docs-site dev --push if: github.ref == 'refs/heads/main' - if: github.ref == 'refs/heads/docs-update' || startsWith(github.ref, 'refs/tags/') id: check-version uses: samuelcolvin/check-python-version@ee87cddb8049d2694cc03badc8569765a05cef00 # v5 with: version_file_path: 'pydantic/version.py' skip_env_check: true - run: PYTHONPATH="$PWD${PYTHONPATH:+:${PYTHONPATH}}" uv run mike deploy -b docs-site ${STEPS_CHECK_VERSION_OUTPUTS_VERSION_MAJOR_MINOR} latest --update-aliases --push if: ${{ (github.ref == 'refs/heads/docs-update' || startsWith(github.ref, 'refs/tags/')) && !fromJSON(steps.check-version.outputs.IS_PRERELEASE) }} env: PYDANTIC_VERSION: v${{ steps.check-version.outputs.VERSION }} STEPS_CHECK_VERSION_OUTPUTS_VERSION_MAJOR_MINOR: ${{ steps.check-version.outputs.VERSION_MAJOR_MINOR }} - run: uv run python docs/plugins/algolia.py upload env: ALGOLIA_WRITE_API_KEY: ${{ secrets.ALGOLIA_WRITE_API_KEY }} pydantic-pydantic-ba0aa01/.github/workflows/integration.yml000066400000000000000000000023431517143232300242530ustar00rootroot00000000000000name: Pydantic Family Integration Tests on: schedule: - cron: '21 3 * * 1,2,3,4,5' workflow_dispatch: {} permissions: contents: read jobs: test-pydantic-settings: name: Test pydantic settings runs-on: ubuntu-latest strategy: matrix: python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: python-version: ${{ matrix.python-version }} - name: Run tests run: make test-pydantic-settings test-pydantic-extra-types: name: Test pydantic extra types runs-on: ubuntu-latest strategy: matrix: python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: python-version: ${{ matrix.python-version }} - name: Run tests run: make test-pydantic-extra-types pydantic-pydantic-ba0aa01/.github/workflows/third-party.yml000066400000000000000000001031351517143232300242000ustar00rootroot00000000000000# This workflow is a daily cron job, inspired by: # https://github.com/python/typing_extensions/blob/main/.github/workflows/third_party.yml. # Running the tests of various third-party libraries that use Pydantic. This helps us spot regressions early, and helps # flag when third-party libraries are making incorrect assumptions that might cause them to break when we cut a new release. # Instructions: # - The CI should be as close as possible to the original project's workflows. # - Use the checkout action to clone Pydantic with a custom path (e.g. `path: pydantic-latest`). # - Make sure Pydantic is installed in editable mode (e.g. `uv pip install -e ./pydantic-latest`) # so that the path appears in the `pip list` output (and so we can be assured Pydantic was properly # installed from the provided path). # - If using `uv run`, make use to use the `--no-sync`, because uv has the nasty habit of syncing the venv # on each `uv run` invocation, which will reinstall the locked `pydantic`/`pydantic-core` version. name: Third party tests on: schedule: - cron: '0 12 * * *' # Daily at midnight UTC pull_request: branches: [main] # Can be manually triggered from the Actions tab, if needed: workflow_dispatch: permissions: contents: read env: # https://github.com/pytest-dev/pytest/issues/7443#issuecomment-656642591: FORCE_COLOR: 1 # https://pip.pypa.io/en/stable/cli/pip_install/#cmdoption-progress-bar PIP_PROGRESS_BAR: off concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true jobs: test-fastapi: name: Test FastAPI (main branch) on Python ${{ matrix.python-version }} # If 'schedule' was the trigger, don't run it on contributors' forks if: | github.event_name == 'workflow_dispatch' || (github.event_name == 'schedule' && github.repository == 'pydantic/pydantic') || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'third-party-tests')) runs-on: ubuntu-latest strategy: fail-fast: false matrix: python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] steps: - name: Checkout FastAPI uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: repository: fastapi/fastapi persist-credentials: false - name: Checkout Pydantic uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: pydantic-latest persist-credentials: false - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: python-version: ${{ matrix.python-version }} - name: Install FastAPI dependencies run: | uv sync --locked --no-dev --group tests --extra all uv pip uninstall pydantic pydantic-core uv pip install -e ./pydantic-latest -e ./pydantic-latest/pydantic-core - name: List installed dependencies run: uv pip list - name: Run FastAPI tests run: PYTHONPATH=./docs_src uv run --no-project --no-sync pytest tests test-sqlmodel: name: Test SQLModel (main branch) on Python ${{ matrix.python-version }} # If 'schedule' was the trigger, don't run it on contributors' forks if: | github.event_name == 'workflow_dispatch' || (github.event_name == 'schedule' && github.repository == 'pydantic/pydantic') || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'third-party-tests')) runs-on: ubuntu-latest strategy: fail-fast: false matrix: python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] steps: - name: Checkout SQLModel uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: repository: fastapi/sqlmodel persist-credentials: false - name: Checkout Pydantic uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: pydantic-latest persist-credentials: false - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: python-version: ${{ matrix.python-version }} - name: Install SQLModel dependencies run: | uv sync --locked --no-dev --group tests uv pip uninstall pydantic pydantic-core uv pip install -e ./pydantic-latest -e ./pydantic-latest/pydantic-core - name: List installed dependencies run: uv pip list - run: mkdir coverage - name: Run SQLModel tests run: uv run --no-sync pytest tests test-beanie: name: Test Beanie (main branch) on Python ${{ matrix.python-version }} # If 'schedule' was the trigger, don't run it on contributors' forks if: | github.event_name == 'workflow_dispatch' || (github.event_name == 'schedule' && github.repository == 'pydantic/pydantic') || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'third-party-tests')) runs-on: ubuntu-latest strategy: fail-fast: false matrix: # Testing on a single version to avoid reaching Docker API limits: python-version: ['3.13'] steps: - name: Checkout Beanie uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: repository: BeanieODM/beanie persist-credentials: false - name: Checkout Pydantic uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: pydantic-latest persist-credentials: false - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: ${{ matrix.python-version }} - name: Start MongoDB uses: supercharge/mongodb-github-action@315db7fe45ac2880b7758f1933e6e5d59afd5e94 # 1.12.1 with: mongodb-version: '8.0' mongodb-replica-set: test-rs - name: Install Beanie dependencies run: | pip install .[test,ci] pip uninstall --yes pydantic pydantic-core pip install -e ./pydantic-latest -e ./pydantic-latest/pydantic-core - name: List installed dependencies run: pip list - name: Run Beanie tests run: pytest -v test-openapi-python-client: name: Test openapi-python-client (main branch) on Python ${{ matrix.python-version }} # If 'schedule' was the trigger, don't run it on contributors' forks if: | github.event_name == 'workflow_dispatch' || (github.event_name == 'schedule' && github.repository == 'pydantic/pydantic') || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'third-party-tests')) runs-on: ubuntu-latest strategy: fail-fast: false matrix: python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] steps: - name: Checkout openapi-python-client uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: repository: openapi-generators/openapi-python-client persist-credentials: false - name: Checkout Pydantic uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: pydantic-latest persist-credentials: false - name: Set up PDM uses: pdm-project/setup-pdm@973541a5febeafcfdadf8a51211435be6ecfd90f # v4.5 with: python-version: ${{ matrix.python-version }} - name: Install openapi-python-client dependencies run: | pdm install --quiet pdm run python -m ensurepip pdm run python -m pip uninstall --yes pydantic pydantic-core pdm run python -m pip install -e ./pydantic-latest -e ./pydantic-latest/pydantic-core - name: List installed dependencies run: pdm list - name: Run openapi-python-client tests run: pdm test env: TASKIPY: true test-pandera: name: Test Pandera (main branch) on Python ${{ matrix.python-version }} # If 'schedule' was the trigger, don't run it on contributors' forks if: | github.event_name == 'workflow_dispatch' || (github.event_name == 'schedule' && github.repository == 'pydantic/pydantic') || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'third-party-tests')) runs-on: ubuntu-latest strategy: fail-fast: false matrix: python-version: ['3.9', '3.10', '3.11', '3.12'] steps: - name: Checkout Pandera uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: repository: unionai-oss/pandera persist-credentials: false - name: Checkout Pydantic uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: pydantic-latest persist-credentials: false - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: ${{ matrix.python-version }} - name: Install Pandera dependencies run: | pip install uv uv sync --no-progress --extra pandas --extra fastapi --extra pandas --group dev --group testing --group docs uv pip uninstall --system pydantic pydantic-core uv pip install --system -e ./pydantic-latest - name: List installed dependencies run: uv pip list - name: Run Pandera tests # Pandera's CI uses nox sessions which encapsulate the logic to install a specific Pydantic version. # Instead, manually run pytest (we run core, pandas and FastAPI tests): run: uv run --no-sync pytest tests/base tests/pandas tests/fastapi test-odmantic: name: Test ODMantic (main branch) on Python ${{ matrix.python-version }} # If 'schedule' was the trigger, don't run it on contributors' forks if: | github.event_name == 'workflow_dispatch' || (github.event_name == 'schedule' && github.repository == 'pydantic/pydantic') || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'third-party-tests')) runs-on: ubuntu-latest strategy: fail-fast: false matrix: python-version: ['3.9', '3.10', '3.11'] steps: - name: Checkout ODMantic uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: repository: art049/odmantic persist-credentials: false - name: Checkout Pydantic uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: pydantic-latest persist-credentials: false - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: ${{ matrix.python-version }} - name: Set up uv uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 - name: Mongo service run: bash mongodb-cluster/run.sh env: MODE: standalone VERSION: '6' - name: Install ODMantic dependencies run: | uv sync --locked --no-dev --extra test uv pip uninstall pydantic pydantic-core uv pip install -e ./pydantic-latest -e ./pydantic-latest/pydantic-core - name: List installed dependencies run: uv pip list - name: Run ODMantic tests # Disabled tests, as per https://github.com/art049/odmantic/issues/512: run: uv run --no-sync pytest tests -k 'not test_custom_bson_serializable and not test_sync_custom_bson_serializable and not test_with_bson_serializer_override_builtin_bson' env: TEST_MONGO_URI: mongodb://localhost:27017/ TEST_MONGO_MODE: standalone test-polar: name: Test Polar (main branch) on Python ${{ matrix.python-version }} # If 'schedule' was the trigger, don't run it on contributors' forks if: | github.event_name == 'workflow_dispatch' || (github.event_name == 'schedule' && github.repository == 'pydantic/pydantic') || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'third-party-tests')) env: POLAR_ENV: testing POLAR_EMAIL_RENDERER_BINARY_PATH: ${{ github.workspace }}/server/emails/bin/react-email-pkg runs-on: ubuntu-latest strategy: fail-fast: false matrix: python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] services: postgres: image: postgres:15.1-bullseye env: POSTGRES_USER: polar POSTGRES_PASSWORD: polar POSTGRES_DB: polar_test POSTGRES_PORT: 5432 options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 ports: - 5432:5432 minio: image: bitnamilegacy/minio:2024.5.28 ports: - 9000:9000 - 9001:9001 env: MINIO_ROOT_USER: polar MINIO_ROOT_PASSWORD: polarpolar options: >- --health-cmd "curl -I http://127.0.0.1:9000/minio/health/live" --health-interval 10s --health-timeout 5s --health-retries 5 steps: - name: Checkout polar uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: repository: polarsource/polar persist-credentials: false - name: 💿 MinIO Setup working-directory: ./server/.minio env: MINIO_HOST: 127.0.0.1 MINIO_ROOT_USER: polar MINIO_ROOT_PASSWORD: polarpolar ACCESS_KEY: polar-development SECRET_ACCESS_KEY: polar123456789 BUCKET_NAME: polar-s3 BUCKET_TESTING_NAME: testing-polar-s3 POLICY_FILE: policy.json run: bash github.sh - uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 with: package_json_file: server/emails/package.json - name: 📬 Setup Node.js environment for server/emails uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: node-version-file: server/emails/.node-version cache: 'pnpm' cache-dependency-path: 'clients/pnpm-lock.yaml' - name: 📬 Build server/emails working-directory: server/emails run: pnpm install --frozen-lockfile && pnpm build - name: Checkout Pydantic uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: pydantic-latest persist-credentials: false - name: Install uv uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: ${{ matrix.python-version }} - name: 🔧 uv install working-directory: ./server run: | uv sync --no-progress --dev uv pip uninstall pydantic uv pip install -e ./../pydantic-latest uv run --no-sync task generate_dev_jwks - name: List installed dependencies working-directory: ./server run: uv pip list - name: ⚗️ alembic migrate working-directory: ./server run: uv run --no-sync task db_migrate - name: ⚗️ alembic check working-directory: ./server run: uv run --no-sync alembic check - name: 🐍 Run polar tests (pytest) working-directory: ./server run: uv run --no-sync pytest -n auto --no-cov test-bentoml: name: Test BentoML (main branch) on Python ${{ matrix.python-version }} # If 'schedule' was the trigger, don't run it on contributors' forks if: | github.event_name == 'workflow_dispatch' || (github.event_name == 'schedule' && github.repository == 'pydantic/pydantic') || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'third-party-tests')) runs-on: ubuntu-latest strategy: fail-fast: false matrix: python-version: ['3.9', '3.11', '3.12'] steps: - name: Checkout BentoML uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: repository: bentoml/BentoML persist-credentials: false - name: Checkout Pydantic uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: pydantic-latest persist-credentials: false # Note: BentoML workflow uses nox sessions which don't allow installing # the custom Pydantic version. Instead, we manually set up the env. - name: Set up PDM uses: pdm-project/setup-pdm@973541a5febeafcfdadf8a51211435be6ecfd90f # v4.5 with: python-version: ${{ matrix.python-version }} - name: Install BentoML dependencies run: | pdm sync -G grpc,io,testing --quiet pdm run python -m ensurepip pdm run python -m pip uninstall --yes pydantic pydantic-core pdm run python -m pip install -e ./pydantic-latest -e ./pydantic-latest/pydantic-core - name: List installed dependencies run: pdm list - name: Run BentoML tests run: pdm run pytest -n auto tests/unit env: BENTOML_DO_NOT_TRACK: True PYTEST_PLUGINS: bentoml.testing.pytest.plugin test-semantic-kernel: name: Test Semantic Kernel (main branch) on Python ${{ matrix.python-version }} # If 'schedule' was the trigger, don't run it on contributors' forks if: | github.event_name == 'workflow_dispatch' || (github.event_name == 'schedule' && github.repository == 'pydantic/pydantic') || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'third-party-tests')) runs-on: ubuntu-latest strategy: fail-fast: false matrix: python-version: ['3.10', '3.11', '3.12'] steps: - name: Checkout Semantic Kernel uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: repository: microsoft/semantic-kernel persist-credentials: false - name: Checkout Pydantic uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: pydantic-latest persist-credentials: false - name: Install uv uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: python-version: ${{ matrix.python-version }} working-directory: python - name: Install Semantic Kernel dependencies working-directory: ./python run: | uv sync --no-progress --all-extras --dev --prerelease=if-necessary-or-explicit uv pip uninstall pydantic uv pip install -e ../pydantic-latest - name: List installed dependencies working-directory: ./python run: uv pip list - name: Run Semantic Kernel tests working-directory: ./python run: uv run --frozen --no-sync pytest ./tests/unit --ignore=tests/unit/processes/dapr_runtime test-langchain: name: Test LangChain (main branch) on Python ${{ matrix.python-version }} # If 'schedule' was the trigger, don't run it on contributors' forks if: | github.event_name == 'workflow_dispatch' || (github.event_name == 'schedule' && github.repository == 'pydantic/pydantic') || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'third-party-tests')) runs-on: ubuntu-latest strategy: fail-fast: false matrix: python-version: ['3.10', '3.11', '3.12', '3.13'] steps: - name: Checkout Langchain uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: repository: langchain-ai/langchain persist-credentials: false - name: Checkout Pydantic uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: pydantic-latest persist-credentials: false - name: Install uv uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: python-version: ${{ matrix.python-version }} - name: Install LangChain dependencies run: | uv sync --no-progress --directory ./libs/core --group test uv pip uninstall --directory ./libs/core pydantic uv pip install --directory ./libs/core -e ../../pydantic-latest uv sync --no-progress --directory ./libs/langchain --group test uv pip uninstall --directory ./libs/langchain pydantic uv pip install --directory ./libs/langchain -e ../../pydantic-latest uv sync --no-progress --directory ./libs/langchain_v1 --group test uv pip uninstall --directory ./libs/langchain_v1 pydantic uv pip install --directory ./libs/langchain_v1 -e ../../pydantic-latest - name: List installed core dependencies run: uv pip list --directory ./libs/core - name: List installed LangChain v0.x dependencies run: uv pip list --directory ./libs/langchain - name: List installed LangChain v1.x dependencies run: uv pip list --directory ./libs/langchain_v1 - name: Run LangChain core tests working-directory: ./libs/core run: UV_NO_SYNC=1 make test - name: Run LangChain v0.x main tests working-directory: ./libs/langchain run: UV_NO_SYNC=1 make test - name: Run LangChain v1.x main tests working-directory: ./libs/langchain_v1 run: UV_NO_SYNC=1 make test test-dify: name: Test Dify (main branch) on Python ${{ matrix.python-version }} # If 'schedule' was the trigger, don't run it on contributors' forks if: | github.event_name == 'workflow_dispatch' || (github.event_name == 'schedule' && github.repository == 'pydantic/pydantic') || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'third-party-tests')) runs-on: ubuntu-latest strategy: matrix: python-version: ['3.12'] steps: - name: Checkout Dify uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: repository: langgenius/dify persist-credentials: false - name: Checkout Pydantic uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: pydantic-latest persist-credentials: false - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: ${{ matrix.python-version }} - name: Install uv shell: bash run: pip install uv~=0.7.0 - name: Install Dify dependencies run: | uv sync --no-progress --directory api --dev uv pip --directory api uninstall pydantic pydantic-core uv pip --directory api install -e ../pydantic-latest -e ../pydantic-latest/pydantic-core - name: List installed dependencies run: uv pip --directory api list - name: Run Dify unit tests run: uv run --no-sync --project api bash dev/pytest/pytest_unit_tests.sh test-cadwyn: name: Test Cadwyn (main branch) on Python ${{ matrix.python-version }} # If 'schedule' was the trigger, don't run it on contributors' forks if: | github.event_name == 'workflow_dispatch' || (github.event_name == 'schedule' && github.repository == 'pydantic/pydantic') || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'third-party-tests')) runs-on: ubuntu-latest strategy: fail-fast: false matrix: python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] steps: - name: Checkout Cadwyn uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: repository: zmievsa/cadwyn persist-credentials: false - name: Checkout Pydantic uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: pydantic-latest persist-credentials: false - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: python-version: ${{ matrix.python-version }} activate-environment: true - name: Install Cadwyn dependencies run: | uv sync --no-progress --dev --all-extras uv pip install -e ./pydantic-latest - name: List installed dependencies run: uv pip list - name: Run Cadwyn tests run: uv run --no-sync pytest tests docs_src test-pydantic-xml: name: Test pydantic-xml (main branch) on Python ${{ matrix.python-version }} # If 'schedule' was the trigger, don't run it on contributors' forks if: | github.event_name == 'workflow_dispatch' || (github.event_name == 'schedule' && github.repository == 'pydantic/pydantic') || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'third-party-tests')) runs-on: ubuntu-latest strategy: fail-fast: false matrix: python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] steps: - name: Checkout pydantic-xml uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: repository: dapper91/pydantic-xml persist-credentials: false - name: Checkout Pydantic uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: pydantic-latest persist-credentials: false - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: ${{ matrix.python-version }} - name: Install pydantic-xml dependencies run: | python -m pip install --upgrade pip pip install poetry poetry install --no-root -E lxml pip uninstall pydantic pip install -e ./pydantic-latest/pydantic-core -e ./pydantic-latest - name: List installed dependencies run: pip list - name: Run pydantic-xml tests run: PYTHONPATH="$(pwd):$PYTHONPATH" poetry run pytest tests test-redis-om: name: Test Redis OM Python (main branch) on Python ${{ matrix.python-version }} if: | github.event_name == 'workflow_dispatch' || (github.event_name == 'schedule' && github.repository == 'pydantic/pydantic') || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'third-party-tests')) runs-on: ubuntu-latest strategy: fail-fast: false matrix: python-version: ['3.10', '3.11', '3.12', '3.13'] services: redis: image: redis/redis-stack:latest # zizmor: ignore[unpinned-images] -- intentionally using latest for third-party compatibility testing ports: # Maps port 6379 on service container to the host - 6379:6379 # Set health checks to wait until redis has started options: >- --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5 env: INSTALL_DIR: ${{ github.workspace }}/redis steps: - name: Checkout Redis OM Python uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: repository: redis/redis-om-python persist-credentials: false - name: Checkout Pydantic uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: pydantic-latest persist-credentials: false - name: Install uv uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 - name: Setup Python ${{ matrix.python-version }} uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | uv sync uv pip uninstall pydantic pydantic-core uv pip install -e ./pydantic-latest -e ./pydantic-latest/pydantic-core - name: Make sync version of library (redis_om) run: make sync - name: List installed dependencies run: uv pip list - name: Run Redis OM Python tests env: REDIS_OM_URL: 'redis://localhost:6379?decode_responses=True' run: | make test test-django-ninja: name: Test Django Ninja (main branch) on Python ${{ matrix.python-version }} if: | github.event_name == 'workflow_dispatch' || (github.event_name == 'schedule' && github.repository == 'pydantic/pydantic') || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'third-party-tests')) runs-on: ubuntu-latest strategy: fail-fast: false matrix: python-version: ['3.10', '3.11', '3.12', '3.13'] steps: - name: Checkout Django Ninja uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: repository: vitalik/django-ninja persist-credentials: false - name: Checkout Pydantic uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: pydantic-latest persist-credentials: false - name: Set up Python uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: ${{ matrix.python-version }} - name: Install Django Ninja dependencies run: pip install pytest pytest-asyncio pytest-django psycopg2-binary 'django~=5.2.7' ./pydantic-latest ./pydantic-latest/pydantic-core # For some reason, tests can't run properly if the pydantic sources are around: - run: rm -rd ./pydantic-latest - name: List installed dependencies run: pip list - name: Run Django Ninja tests run: pytest test-fastdepends: name: Test FastDepends (main branch) on Python ${{ matrix.python-version }} if: | github.event_name == 'workflow_dispatch' || (github.event_name == 'schedule' && github.repository == 'pydantic/pydantic') || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'third-party-tests')) runs-on: ubuntu-latest strategy: fail-fast: false matrix: python-version: ['3.10', '3.11', '3.12', '3.13'] steps: - name: Checkout FastDepends uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: repository: Lancetnik/FastDepends persist-credentials: false - name: Checkout Pydantic uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: pydantic-latest persist-credentials: false - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0 with: python-version: ${{ matrix.python-version }} - name: Install FastDepends dependencies run: | uv venv --python ${{ matrix.python-version }} uv sync --group test uv pip uninstall pydantic uv pip install -e ./pydantic-latest - name: List installed dependencies run: uv pip list - name: Run FastDepends tests run: uv run --no-sync pytest create-issue-on-failure: name: Create an issue if tests failed runs-on: ubuntu-latest needs: - test-fastapi - test-sqlmodel - test-beanie - test-openapi-python-client - test-pandera - test-odmantic - test-polar - test-bentoml - test-semantic-kernel - test-langchain - test-dify - test-cadwyn - test-pydantic-xml - test-redis-om - test-django-ninja - test-fastdepends # Issue report disabled for now due to flakiness: if: | always() && false && github.repository == 'pydantic/pydantic' && github.event_name == 'schedule' && ( needs.test-fastapi.result == 'failure' || needs.test-sqlmodel.result == 'failure' || needs.test-beanie.result == 'failure' || needs.test-openapi-python-client.result == 'failure' || needs.test-pandera.result == 'failure' || needs.test-odmantic.result == 'failure' || needs.test-polar.result == 'failure' || needs.test-semantic-kernel.result == 'failure' || needs.test-bentoml.result == 'failure' || needs.test-langchain.result == 'failure' || needs.test-dify.result == 'failure' || needs.test-cadwyn.result == 'failure' || needs.test-pydantic-xml.result == 'failure' || needs.test-redis-om.result == 'failure' || needs.test-django-ninja.result == 'failure' || needs.test-fastdepends.result == 'failure' ) permissions: issues: write steps: - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 with: script: | await github.rest.issues.create({ owner: 'pydantic', repo: 'pydantic', title: `Third-party tests failed on ${new Date().toDateString()}`, body: 'Run listed here: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}', }) pydantic-pydantic-ba0aa01/.github/workflows/update-pydantic-people.yml000066400000000000000000000006751517143232300263130ustar00rootroot00000000000000name: Pydantic people update on: schedule: - cron: '0 12 1 * *' workflow_dispatch: {} permissions: contents: write pull-requests: write jobs: pydantic-people: runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: ./.github/actions/people with: token: ${{ secrets.GITHUB_TOKEN }} pydantic-pydantic-ba0aa01/.github/workflows/upload-previews.yml000066400000000000000000000026011517143232300250530ustar00rootroot00000000000000name: Upload previews on: # zizmor: ignore[dangerous-triggers] -- workflow_run is used safely here; no code checkout occurs workflow_run: workflows: [CI] types: [completed] permissions: statuses: write jobs: upload-previews: if: ${{ github.event.workflow_run.conclusion == 'success' }} runs-on: ubuntu-latest steps: # DO NOT run actions/checkout here, for security reasons # For details, refer to https://securitylab.github.com/research/github-actions-preventing-pwn-requests/ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: '3.10' - run: pip install smokeshow - uses: dawidd6/action-download-artifact@8a338493df3d275e4a7a63bcff3b8fe97e51a927 # v19 with: workflow: ci.yml commit: ${{ github.event.workflow_run.head_sha }} - run: smokeshow upload coverage-html env: SMOKESHOW_GITHUB_STATUS_DESCRIPTION: Coverage {coverage-percentage} # 5 is set here while V2 is in development and coverage is far from complete SMOKESHOW_GITHUB_COVERAGE_THRESHOLD: 91 SMOKESHOW_GITHUB_CONTEXT: coverage SMOKESHOW_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SMOKESHOW_GITHUB_PR_HEAD_SHA: ${{ github.event.workflow_run.head_sha }} SMOKESHOW_AUTH_KEY: ${{ secrets.SMOKESHOW_AUTH_KEY }} pydantic-pydantic-ba0aa01/.github/zizmor.yml000066400000000000000000000001311517143232300212160ustar00rootroot00000000000000rules: secrets-outside-env: disable: true superfluous-actions: disable: true pydantic-pydantic-ba0aa01/.gitignore000066400000000000000000000013531517143232300176000ustar00rootroot00000000000000# Virtual environments env/ env3*/ venv/ .venv/ __pypackages__/ # IDEs and editors .idea/ .vscode/ # Package distribution and build files *.egg-info/ dist/ /build/ _build/ # Python bytecode and cache files *.py[cod] .cache/ /.ghtopdep_cache/ .hypothesis .mypy_cache/ .pytest_cache/ /.ruff_cache/ # Benchmark and test files /benchmarks/*.json /tests/benchmarks/*.json /htmlcov/ /codecov.sh /coverage.lcov .coverage /test*.py run_mypy_on_file.py # Documentation files /docs/changelog.md /docs/*.whl /docs/theme/mkdocs_run_deps.html /site/ /site.zip # Project-specific files pydantic/*.c pydantic/*.so /fastapi/ .mypy-configs/ # Other files and folders .python-version .DS_Store .auto-format /sandbox/ /worktrees/ # Rust build files /target/ pydantic-pydantic-ba0aa01/.hyperlint/000077500000000000000000000000001517143232300177025ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/.hyperlint/.vale.ini000066400000000000000000000002431517143232300214070ustar00rootroot00000000000000StylesPath = styles MinAlertLevel = suggestion Vocab = hyperlint SkippedScopes = script, style, pre, figure, code, code-block [*] BasedOnStyles = Vale, hyperlint pydantic-pydantic-ba0aa01/.hyperlint/style_guide_test.md000066400000000000000000000002541517143232300236010ustar00rootroot00000000000000 # This ia a test file it will flag errors like on pydantic. It won't flag on validators. but it won't flag errors on SDK or SDKs or APIs anymore. This is is an issue. pydantic-pydantic-ba0aa01/.hyperlint/styles/000077500000000000000000000000001517143232300212255ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/.hyperlint/styles/config/000077500000000000000000000000001517143232300224725ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/.hyperlint/styles/config/vocabularies/000077500000000000000000000000001517143232300251515ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/.hyperlint/styles/config/vocabularies/hyperlint/000077500000000000000000000000001517143232300271675ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/.hyperlint/styles/config/vocabularies/hyperlint/accept.txt000066400000000000000000000001551517143232300311700ustar00rootroot00000000000000validator Pydantic validators namespace Hyperlint preprocess tokenization tokenizer tzdata API APIs SDKs SDK pydantic-pydantic-ba0aa01/.hyperlint/styles/hyperlint/000077500000000000000000000000001517143232300232435ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/.hyperlint/styles/hyperlint/repeatedWords.yml000066400000000000000000000002031517143232300265710ustar00rootroot00000000000000extends: repetition message: '''%s'' is repeated, did you mean to repeat this word?' level: error alpha: true tokens: - '[^\s]+' pydantic-pydantic-ba0aa01/.markdownlint.yaml000066400000000000000000000016271517143232300212670ustar00rootroot00000000000000# See rule aliases: https://github.com/DavidAnson/markdownlint#rules--aliases line-length: false ul-style: style: asterisk emphasis-style: style: asterisk # need to indent with 4 spaces to render properly ul-indent: indent: 4 # H1 headings are automatically inserted by mkdocs first-line-h1: false # Allow same heading name if the parent is different no-duplicate-heading: siblings_only: true # Allow inline HTML to support line breaks etc. no-inline-html: false # Need to disable in order to support PyMdown Tabbed extension and admonitions # See: https://facelessuser.github.io/pymdown-extensions/extensions/tabbed/ # See: https://squidfunk.github.io/mkdocs-material/reference/admonitions/ code-block-style: false # Disabled in order to support references to API reference-links-images: false # Anchors via attribute lists are not detected, let mkdocs handle anchor validation link-fragments: false pydantic-pydantic-ba0aa01/.pre-commit-config.yaml000066400000000000000000000024161517143232300220720ustar00rootroot00000000000000repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 hooks: - id: no-commit-to-branch # prevent direct commits to main branch - id: check-yaml args: ['--unsafe'] - id: check-toml - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/codespell-project/codespell rev: v2.4.1 hooks: - id: codespell additional_dependencies: - tomli exclude: '^uv\.lock$' - repo: https://github.com/DavidAnson/markdownlint-cli2 rev: v0.18.1 hooks: - id: markdownlint-cli2 - repo: https://github.com/google/yamlfmt rev: v0.21.0 hooks: - id: yamlfmt - repo: https://github.com/zizmorcore/zizmor-pre-commit rev: v1.23.1 hooks: - id: zizmor - repo: local hooks: - id: lint name: Lint entry: make lint-python types: [python] language: system pass_filenames: false - id: lint rust name: Lint Rust entry: make lint-rust types: [rust] language: system pass_filenames: false - id: typecheck name: Typecheck entry: uv run pyright pydantic types: [python] language: system pass_filenames: false pydantic-pydantic-ba0aa01/.yamlfmt.yaml000066400000000000000000000002341517143232300202200ustar00rootroot00000000000000exclude: - docs/plugins/people.yml formatter: type: basic retain_line_breaks_single: true scan_folded_as_literal: true force_quote_style: single pydantic-pydantic-ba0aa01/CITATION.cff000066400000000000000000000023531517143232300175030ustar00rootroot00000000000000cff-version: 1.2.0 title: Pydantic Validation message: 'If you use this software, please cite it as below.' type: software authors: - family-names: Colvin given-names: Samuel - family-names: Jolibois given-names: Eric - family-names: Ramezani given-names: Hasan - family-names: Garcia Badaracco given-names: Adrian - family-names: Dorsey given-names: Terrence - family-names: Montague given-names: David - family-names: Matveenko given-names: Serge - family-names: Trylesinski given-names: Marcelo - family-names: Runkle given-names: Sydney - family-names: Hewitt given-names: David - family-names: Hall given-names: Alex - family-names: Plot given-names: Victorien repository-code: 'https://github.com/pydantic/pydantic' url: 'https://docs.pydantic.dev/latest/' abstract: >- Pydantic Validation is the most widely used data validation library for Python. Fast and extensible, Pydantic Validation plays nicely with your linters/IDE/brain. Define how data should be in pure, canonical Python 3.9+; validate it with Pydantic Validation. keywords: - python - validation - parsing - json-schema - hints - typing license: MIT version: v2.13.3 date-released: 2026-04-20 pydantic-pydantic-ba0aa01/HISTORY.md000066400000000000000000011643101517143232300172770ustar00rootroot00000000000000 ## v2.13.3 (2026-04-20) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.13.3) ### What's Changed #### Fixes * Handle `AttributeError` subclasses with `from_attributes` by @Viicos in [#13096](https://github.com/pydantic/pydantic/pull/13096) ## v2.13.2 (2026-04-17) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.13.2) ### What's Changed #### Fixes * Fix `ValidationInfo.field_name` missing with `model_validate_json()` by @Viicos in [#13084](https://github.com/pydantic/pydantic/pull/13084) ## v2.13.1 (2026-04-15) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.13.1) ### What's Changed #### Fixes * Fix `ValidationInfo.data` missing with `model_validate_json()` by @davidhewitt in [#13079](https://github.com/pydantic/pydantic/pull/13079) ## v2.13.0 (2026-04-13) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.13.0) The highlights of the v2.13 release are available in the [blog post](https://pydantic.dev/articles/pydantic-v2-13-release). Several minor changes (considered non-breaking changes according to our [versioning policy](https://pydantic.dev/docs/validation/2.13/get-started/version-policy/#pydantic-v2)) are also included in this release. Make sure to look into them before upgrading. This release contains the updated `pydantic.v1` namespace, matching version 1.10.26 which includes support for Python 3.14. ### What's Changed See the beta releases for all changes sinces 2.12. #### New Features * Allow default factories of private attributes to take validated model data by @Viicos in [#13013](https://github.com/pydantic/pydantic/pull/13013) #### Changes * Warn when serializing fixed length tuples with too few items by @arvindsaripalli in [#13016](https://github.com/pydantic/pydantic/pull/13016) #### Fixes * Change type of `Any` when synthesizing `_build_sources` for `BaseSettings.__init__()` signature in the mypy plugin by @Viicos in [#13049](https://github.com/pydantic/pydantic/pull/13049) * Fix model equality when using runtime `extra` configuration by @Viicos in [#13062](https://github.com/pydantic/pydantic/pull/13062) #### Packaging * Add zizmor for GitHub Actions workflow linting by @Viicos in [#13039](https://github.com/pydantic/pydantic/pull/13039) * Update jiter to v0.14.0 to fix a segmentation fault on musl Linux by @Viicos in [#13064](https://github.com/pydantic/pydantic/pull/13064) ### New Contributors * @arvindsaripalli made their first contribution in [#13016](https://github.com/pydantic/pydantic/pull/13016) ## v2.13.0b3 (2026-03-31) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.13.0b3) ### What's Changed #### New Features * Add `ascii_only` option to `StringConstraints` by @ai-man-codes in [#12907](https://github.com/pydantic/pydantic/pull/12907) * Support `exclude_if` in computed fields by @andresliszt in [#12748](https://github.com/pydantic/pydantic/pull/12748) * Push down constraints in unions involving `MISSING` sentinel by @Viicos in [#12908](https://github.com/pydantic/pydantic/pull/12908) #### Changes * Track extra fields set after init in `model_fields_set` by @navalprakhar in [#12817](https://github.com/pydantic/pydantic/pull/12817) * Do not include annotations that are not part of named tuple fields by @galuszkak in [#12951](https://github.com/pydantic/pydantic/pull/12951) * No longer fall back to trying all union members when the variant selected by discriminator fails to serialize by @navalprakhar in [#12825](https://github.com/pydantic/pydantic/pull/12825) #### Fixes * Support discriminator metadata outside union type alias by @Viicos in [#12785](https://github.com/pydantic/pydantic/pull/12785) * Respect `extras_schema` when only `extra_fields_behavior` is set on the config in JSON Schema generation for typed dictionaries by @Viicos in [#12810](https://github.com/pydantic/pydantic/pull/12810) * Ensure `__pydantic_private__` is set in `model_construct()` with user-defined `model_post_init()` by @nightcityblade in [#12816](https://github.com/pydantic/pydantic/pull/12816) * Handle all schema generation errors in `InstanceOf` by @Viicos in [#12705](https://github.com/pydantic/pydantic/pull/12705) * Allow dynamic models created with `create_model()` to be used as annotations in the Mypy plugin by @Br1an67 in [#12879](https://github.com/pydantic/pydantic/pull/12879) * Check for `PlaceholderNode` in Mypy plugin by @Viicos in [#12929](https://github.com/pydantic/pydantic/pull/12929) * Try other branches in smart union in case of omit errors by @mikeedjones in [#12758](https://github.com/pydantic/pydantic/pull/12758) * Patch unset attributes with `MISSING` during model serialization with `exclude_unset` by @davidhewitt in [#12905](https://github.com/pydantic/pydantic/pull/12905) * Ensure custom `__init__()` is called when using `model_validate_strings()` by @siewcapital in [#12897](https://github.com/pydantic/pydantic/pull/12897) #### Packaging * Add riscv64 build target for manylinux by @boosterl in [#12723](https://github.com/pydantic/pydantic/pull/12723) ### New Contributors * @kelsonbrito50 made their first contribution in [#12860](https://github.com/pydantic/pydantic/pull/12860) * @boosterl made their first contribution in [#12723](https://github.com/pydantic/pydantic/pull/12723) * @adityagiri3600 made their first contribution in [#12868](https://github.com/pydantic/pydantic/pull/12868) * @navalprakhar made their first contribution in [#12817](https://github.com/pydantic/pydantic/pull/12817) * @Br1an67 made their first contribution in [#12879](https://github.com/pydantic/pydantic/pull/12879) * @rmorshea made their first contribution in [#12910](https://github.com/pydantic/pydantic/pull/12910) * @N3XT3R1337 made their first contribution in [#12922](https://github.com/pydantic/pydantic/pull/12922) * @ai-man-codes made their first contribution in [#12907](https://github.com/pydantic/pydantic/pull/12907) * @Yume05-dev made their first contribution in [#12953](https://github.com/pydantic/pydantic/pull/12953) * @galuszkak made their first contribution in [#12951](https://github.com/pydantic/pydantic/pull/12951) * @siewcapital made their first contribution in [#12897](https://github.com/pydantic/pydantic/pull/12897) ## v2.13.0b2 (2026-02-24) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.13.0b2) ### What's Changed #### Fixes * Fix backported V1 namespace by @Viicos in [#12855](https://github.com/pydantic/pydantic/pull/12855) * Allow any type form to be used in `validate_as()` by @bledden in [#12846](https://github.com/pydantic/pydantic/pull/12846) * Fix walrus operator precedence in `UrlConstraints.__get_pydantic_core_schema__()` by @bysiber in [#12826](https://github.com/pydantic/pydantic/pull/12826) ### New Contributors * @bledden made their first contribution in [#12846](https://github.com/pydantic/pydantic/pull/12846) * @bysiber made their first contribution in [#12827](https://github.com/pydantic/pydantic/pull/12827) ## v2.13.0b1 (2026-02-23) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.13.0b1) This is the first beta release of the 2.13 version, mainly providing bug fixes and performance improvements for validation and serialization. Notable changes include: * Add a new `polymorphic_serialization` option, solving issues with `serialize_as_any` introduced in 2.12. * Latest V1.10.26 release under the `pydantic.v1` namespace. This version includes support for Python 3.14. * The [`pydantic-core`](https://github.com/pydantic/pydantic-core/) repository was merged inside the main `pydantic` one. ### What's Changed #### New Features * Add `polymorphic_serialization` option by @davidhewitt in [#12518](https://github.com/pydantic/pydantic/pull/12518) * Support Root models with `Literal` root types as discriminator field types by @YassinNouh21 in [#12680](https://github.com/pydantic/pydantic/pull/12680) #### Changes * Migrate `pydantic-core` CI by @Viicos in [#12752](https://github.com/pydantic/pydantic/pull/12752) * Import `pydantic-core` into pydantic by @davidhewitt in [#12481](https://github.com/pydantic/pydantic/pull/12481) * Backport V1 changes up to v1.10.26 by @Viicos in [#12663](https://github.com/pydantic/pydantic/pull/12663) * Use the `complex()` constructor unconditionally when validating `complex` Python data by @tanmaymunjal in [#12498](https://github.com/pydantic/pydantic/pull/12498) * Add support for three-tuple input for `Decimal` by @tanmaymunjal in [#12500](https://github.com/pydantic/pydantic/pull/12500) * Align `@field_serializer` logic with `@field_validator` by @Viicos in [#12577](https://github.com/pydantic/pydantic/pull/12577) * Make `PydanticUserError` a `RuntimeError` instead of a `TypeError` by @poliakovva in [#12579](https://github.com/pydantic/pydantic/pull/12579) * Remove redundant serialization attempts in nested unions by @davidhewitt in [#12604](https://github.com/pydantic/pydantic/pull/12604) * Copy `root` value when making root model shallow copies by @YassinNouh21 in [#12679](https://github.com/pydantic/pydantic/pull/12679) * Ensure deterministic JSON schema defaults by sorting sets by @drshvik in [#12760](https://github.com/pydantic/pydantic/pull/12760) #### Performance * Refactor `DecoratorInfos.build()` implementation by @Viicos in [#12536](https://github.com/pydantic/pydantic/pull/12536) * Cache compiled regex in `pydantic-core` by @Viicos in [#12549](https://github.com/pydantic/pydantic/pull/12549) * Optimize creation of `Literal` validators by @davidhewitt in [#12569](https://github.com/pydantic/pydantic/pull/12569) * Optimize implementation of `LookupKey` by @davidhewitt in [#12571](https://github.com/pydantic/pydantic/pull/12571) * Use python strings for field names by @davidhewitt in [#12631](https://github.com/pydantic/pydantic/pull/12631) * Optimize datetime formatting code by @davidhewitt in [#12626](https://github.com/pydantic/pydantic/pull/12626) * Validate JSON model data by iteration by @davidhewitt in [#12550](https://github.com/pydantic/pydantic/pull/12550) * Optimize annotations evaluation of Pydantic models by @Viicos in [#12681](https://github.com/pydantic/pydantic/pull/12681) * Optimize `FieldInfo._copy()` by @Viicos in [#12727](https://github.com/pydantic/pydantic/pull/12727) #### Fixes * Fix `FieldInfo` rebuilding when parameterizing generic models with an `Annotated` type by @Viicos in [#12463](https://github.com/pydantic/pydantic/pull/12463) * Fix nested model schema deduplication in JSON schema generation by @marwan-alloreview in [#12494](https://github.com/pydantic/pydantic/pull/12494) * Fix `InitVar` being ignored when using with the `pydantic.Field()` function by @Viicos in [#12495](https://github.com/pydantic/pydantic/pull/12495) * Fix support for enums with `NamedTuple` as values by @Viicos in [#12506](https://github.com/pydantic/pydantic/pull/12506) * Do not delete mock validator/serializer in `rebuild_dataclass()` by @Viicos in [#12513](https://github.com/pydantic/pydantic/pull/12513) * Require test suite to pass with free threading, switch back to global generic types cache by @davidhewitt in [#12537](https://github.com/pydantic/pydantic/pull/12537) * Refactor `__pydantic_extra__` annotation handling by @Viicos in [#12563](https://github.com/pydantic/pydantic/pull/12563) * Do not add claim of UUID "safety" provision by @davidhewitt in [#12567](https://github.com/pydantic/pydantic/pull/12567) * Use Python hash to perform lookup in tagged union serializer by @davidhewitt in [#12594](https://github.com/pydantic/pydantic/pull/12594) * Do not emit serialization warning `MISSING` sentinel is present in a nested model by @Viicos in [#12635](https://github.com/pydantic/pydantic/pull/12635) * Do not eagerly evaluate annotations in signature logic by @Viicos in [#12660](https://github.com/pydantic/pydantic/pull/12660) * Fix serialization of typed dict unions when `exclude_none` is set by @davidhewitt in [#12677](https://github.com/pydantic/pydantic/pull/12677) * Do not reuse prebuilt serializers/validators on rebuilds by @lmmx in [#12689](https://github.com/pydantic/pydantic/pull/12689) * Fix type annotation of `field_definitions` in `create_model()` by @lehmann-hqs in [#12734](https://github.com/pydantic/pydantic/pull/12734) * Fix incorrect dataclass constructor signature when overriding class `kw_only` with `Field()` by @jfadia in [#12741](https://github.com/pydantic/pydantic/pull/12741) * Use `typing.Union` when replacing types under Python 3.14 by @Viicos in [#12733](https://github.com/pydantic/pydantic/pull/12733) * Improve ImportString error when internal imports fail by @tsembp in [#12740](https://github.com/pydantic/pydantic/pull/12740) * Fix serializing complex numbers with negative zero imaginary part by @lhnwrk in [#12770](https://github.com/pydantic/pydantic/pull/12770) * Preserve custom docstrings on stdlib dataclasses in JSON schema by @nightcityblade in [#12815](https://github.com/pydantic/pydantic/pull/12815) #### Packaging * Bump Rust url dependency from 2.5.4 to 2.5.7 in `pydantic-core` by @dependabot[bot] in [#12508](https://github.com/pydantic/pydantic/pull/12508) * Bump Rust minimum version to 1.88, use edition 2024 by @davidhewitt and @Viicos in [#12551](https://github.com/pydantic/pydantic/pull/12551) and [#12752](https://github.com/pydantic/pydantic/pull/12752) * Bump PyO3 to 0.28, jiter to 0.13 by @davidhewitt in [#12767](https://github.com/pydantic/pydantic/pull/12767) ### New Contributors * @marwan-alloreview made their first contribution in [#12494](https://github.com/pydantic/pydantic/pull/12494) * @tanmaymunjal made their first contribution in [#12498](https://github.com/pydantic/pydantic/pull/12498) * @poliakovva made their first contribution in [#12579](https://github.com/pydantic/pydantic/pull/12579) * @lehmann-hqs made their first contribution in [#12734](https://github.com/pydantic/pydantic/pull/12734) * @jfadia made their first contribution in [#12741](https://github.com/pydantic/pydantic/pull/12741) * @tsembp made their first contribution in [#12740](https://github.com/pydantic/pydantic/pull/12740) * @drshvik made their first contribution in [#12760](https://github.com/pydantic/pydantic/pull/12760) * @lhnwrk made their first contribution in [#12770](https://github.com/pydantic/pydantic/pull/12770) * @nightcityblade made their first contribution in [#12815](https://github.com/pydantic/pydantic/pull/12811) ## v2.12.5 (2025-11-26) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.12.5) This is the fifth 2.12 patch release, addressing an issue with the `MISSING` sentinel and providing several documentation improvements. The next 2.13 minor release will be published in a couple weeks, and will include a new *polymorphic serialization* feature addressing the remaining unexpected changes to the *serialize as any* behavior. * Fix pickle error when using `model_construct()` on a model with `MISSING` as a default value by @ornariece in [#12522](https://github.com/pydantic/pydantic/pull/12522). * Several updates to the documentation by @Viicos. ## v2.12.4 (2025-11-05) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.12.4) This is the fourth 2.12 patch release, fixing more regressions, and reverting a change in the `build()` method of the [`AnyUrl` and Dsn types](https://docs.pydantic.dev/latest/api/networks/). This patch release also fixes an issue with the serialization of IP address types, when `serialize_as_any` is used. The next patch release will try to address the remaining issues with *serialize as any* behavior by introducing a new *polymorphic serialization* feature, that should be used in most cases in place of *serialize as any*. * Fix issue with forward references in parent `TypedDict` classes by @Viicos in [#12427](https://github.com/pydantic/pydantic/pull/12427). This issue is only relevant on Python 3.14 and greater. * Exclude fields with `exclude_if` from JSON Schema required fields by @Viicos in [#12430](https://github.com/pydantic/pydantic/pull/12430) * Revert URL percent-encoding of credentials in the `build()` method of the [`AnyUrl` and Dsn types](https://docs.pydantic.dev/latest/api/networks/) by @davidhewitt in [pydantic-core#1833](https://github.com/pydantic/pydantic-core/pull/1833). This was initially considered as a bugfix, but caused regressions and as such was fully reverted. The next release will include an opt-in option to percent-encode components of the URL. * Add type inference for IP address types by @davidhewitt in [pydantic-core#1868](https://github.com/pydantic/pydantic-core/pull/1868). The 2.12 changes to the `serialize_as_any` behavior made it so that IP address types could not properly serialize to JSON. * Avoid getting default values from defaultdict by @davidhewitt in [pydantic-core#1853](https://github.com/pydantic/pydantic-core/pull/1853). This fixes a subtle regression in the validation behavior of the [`collections.defaultdict`](https://docs.python.org/3/library/collections.html#collections.defaultdict) type. * Fix issue with field serializers on nested typed dictionaries by @davidhewitt in [pydantic-core#1879](https://github.com/pydantic/pydantic-core/pull/1879). * Add more `pydantic-core` builds for the three-threaded version of Python 3.14 by @davidhewitt in [pydantic-core#1864](https://github.com/pydantic/pydantic-core/pull/1864). ## v2.12.3 (2025-10-17) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.12.3) ### What's Changed This is the third 2.12 patch release, fixing issues related to the `FieldInfo` class, and reverting a change to the supported [*after* model validator](https://docs.pydantic.dev/latest/concepts/validators/#model-validators) function signatures. * Raise a warning when an invalid after model validator function signature is raised by @Viicos in [#12414](https://github.com/pydantic/pydantic/pull/12414). Starting in 2.12.0, using class methods for *after* model validators raised an error, but the error wasn't raised concistently. We decided to emit a deprecation warning instead. * Add [`FieldInfo.asdict()`](https://docs.pydantic.dev/latest/api/fields/#pydantic.fields.FieldInfo.asdict) method, improve documentation around `FieldInfo` by @Viicos in [#12411](https://github.com/pydantic/pydantic/pull/12411). This also add back support for mutations on `FieldInfo` classes, that are reused as `Annotated` metadata. **However**, note that this is still *not* a supported pattern. Instead, please refer to the [added example](https://docs.pydantic.dev/latest/examples/dynamic_models/) in the documentation. The [blog post](https://pydantic.dev/articles/pydantic-v2-12-release#changes) section on changes was also updated to document the changes related to `serialize_as_any`. ## v2.12.2 (2025-10-14) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.12.2) ### What's Changed #### Fixes * Release a new `pydantic-core` version, as a corrupted CPython 3.10 `manylinux2014_aarch64` wheel got uploaded ([pydantic-core#1843](https://github.com/pydantic/pydantic-core/pull/1843)). * Fix issue with recursive generic models with a parent model class by @Viicos in [#12398](https://github.com/pydantic/pydantic/pull/12398) ## v2.12.1 (2025-10-13) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.12.1) ### What's Changed This is the first 2.12 patch release, addressing most (but not all yet) regressions from the initial 2.12.0 release. #### Fixes * Do not evaluate annotations when inspecting validators and serializers by @Viicos in [#12355](https://github.com/pydantic/pydantic/pull/12355) * Make sure `None` is converted as `NoneType` in Python 3.14 by @Viicos in [#12370](https://github.com/pydantic/pydantic/pull/12370) * Backport V1 runtime warning when using Python 3.14 by @Viicos in [#12367](https://github.com/pydantic/pydantic/pull/12367) * Fix error message for invalid validator signatures by @Viicos in [#12366](https://github.com/pydantic/pydantic/pull/12366) * Populate field name in `ValidationInfo` for validation of default value by @Viicos in [pydantic-core#1826](https://github.com/pydantic/pydantic-core/pull/1826) * Encode credentials in `MultiHostUrl` builder by @willswire in [pydantic-core#1829](https://github.com/pydantic/pydantic-core/pull/1829) * Respect field serializers when using `serialize_as_any` serialization flag by @davidhewitt in [pydantic-core#1829](https://github.com/pydantic/pydantic-core/pull/1829) * Fix various `RootModel` serialization issues by @davidhewitt in [pydantic-core#1836](https://github.com/pydantic/pydantic-core/pull/1836) ### New Contributors * @willswire made their first contribution in [pydantic-core#1829](https://github.com/pydantic/pydantic-core/pull/1829) ## v2.12.0 (2025-10-07) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.12.0) This is the final 2.12 release. It features the work of 20 external contributors and provides useful new features, along with initial Python 3.14 support. Several minor changes (considered non-breaking changes according to our [versioning policy](https://docs.pydantic.dev/2.12/version-policy/#pydantic-v2)) are also included in this release. Make sure to look into them before upgrading. **Note that Pydantic V1 is not compatible with Python 3.14 and greater**. ### What's Changed See the beta releases for all changes sinces 2.11. #### New Features * Add `extra` parameter to the validate functions by @anvilpete in [#12233](https://github.com/pydantic/pydantic/pull/12233) * Add `exclude_computed_fields` serialization option by @Viicos in [#12334](https://github.com/pydantic/pydantic/pull/12334) * Add `preverse_empty_path` URL options by @Viicos in [#12336](https://github.com/pydantic/pydantic/pull/12336) * Add `union_format` parameter to JSON Schema generation by @Viicos in [#12147](https://github.com/pydantic/pydantic/pull/12147) * Add `__qualname__` parameter for `create_model` by @Atry in [#12001](https://github.com/pydantic/pydantic/pull/12001) #### Fixes * Do not try to infer name from lambda definitions in pipelines API by @Viicos in [#12289](https://github.com/pydantic/pydantic/pull/12289) * Use proper namespace for functions in `TypeAdapter` by @Viicos in [#12324](https://github.com/pydantic/pydantic/pull/12324) * Use `Any` for context type annotation in `TypeAdapter` by @inducer in [#12279](https://github.com/pydantic/pydantic/pull/12279) * Expose `FieldInfo` in `pydantic.fields.__all__` by @Viicos in [#12339](https://github.com/pydantic/pydantic/pull/12339) * Respect `validation_alias` in `@validate_call` by @Viicos in [#12340](https://github.com/pydantic/pydantic/pull/12340) * Use `Any` as context annotation in plugin API by @Viicos in [#12341](https://github.com/pydantic/pydantic/pull/12341) * Use proper `stacklevel` in warnings when possible by @Viicos in [#12342](https://github.com/pydantic/pydantic/pull/12342) #### Packaging * Update V1 copy to v1.10.24 by @Viicos in [#12338](https://github.com/pydantic/pydantic/pull/12338) ### New Contributors * @anvilpete made their first contribution in [#12233](https://github.com/pydantic/pydantic/pull/12233) * @JonathanWindell made their first contribution in [#12327](https://github.com/pydantic/pydantic/pull/12327) * @inducer made their first contribution in [#12279](https://github.com/pydantic/pydantic/pull/12279) * @Atry made their first contribution in [#12001](https://github.com/pydantic/pydantic/pull/12001) ## v2.12.0b1 (2025-10-03) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.12.0b1) This is the first beta release of the upcoming 2.12 release. ### What's Changed #### New Features * Add support for `exclude_if` at the field level by @andresliszt in [#12141](https://github.com/pydantic/pydantic/pull/12141) * Add `ValidateAs` annotation helper by @Viicos in [#11942](https://github.com/pydantic/pydantic/pull/11942) * Add configuration options for validation and JSON serialization of temporal types by @ollz272 in [#12068](https://github.com/pydantic/pydantic/pull/12068) * Add support for PEP 728 by @Viicos in [#12179](https://github.com/pydantic/pydantic/pull/12179) * Add field name in serialization error by @NicolasPllr1 in [pydantic-core#1799](https://github.com/pydantic/pydantic-core/pull/1799) * Add option to preserve empty URL paths by @davidhewitt in [pydantic-core#1789](https://github.com/pydantic/pydantic-core/pull/1789) #### Changes * Raise error if an incompatible `pydantic-core` version is installed by @Viicos in [#12196](https://github.com/pydantic/pydantic/pull/12196) * Remove runtime warning for experimental features by @Viicos in [#12265](https://github.com/pydantic/pydantic/pull/12265) * Warn if registering virtual subclasses on Pydantic models by @Viicos in [#11669](https://github.com/pydantic/pydantic/pull/11669) #### Fixes * Fix `__getattr__()` behavior on Pydantic models when a property raised an `AttributeError` and extra values are present by @raspuchin in [#12106](https://github.com/pydantic/pydantic/pull/12106) * Add test to prevent regression with Pydantic models used as annotated metadata by @Viicos in [#12133](https://github.com/pydantic/pydantic/pull/12133) * Allow to use property setters on Pydantic dataclasses with `validate_assignment` set by @Viicos in [#12173](https://github.com/pydantic/pydantic/pull/12173) * Fix mypy v2 plugin for upcoming mypy release by @cdce8p in [#12209](https://github.com/pydantic/pydantic/pull/12209) * Respect custom title in functions JSON Schema by @Viicos in [#11892](https://github.com/pydantic/pydantic/pull/11892) * Fix `ImportString` JSON serialization for objects with a `name` attribute by @chr1sj0nes in [#12219](https://github.com/pydantic/pydantic/pull/12219) * Do not error on fields overridden by methods in the mypy plugin by @Viicos in [#12290](https://github.com/pydantic/pydantic/pull/12290) #### Packaging * Bump `pydantic-core` to v2.40.1 by @Viicos in [#12314](https://github.com/pydantic/pydantic/pull/12314) ### New Contributors * @raspuchin made their first contribution in [#12106](https://github.com/pydantic/pydantic/pull/12106) * @chr1sj0nes made their first contribution in [#12219](https://github.com/pydantic/pydantic/pull/12219) ## v2.12.0a1 (2025-07-26) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.12.0a1) This is the first alpha release of the upcoming 2.12 release, which adds initial support for Python 3.14. ### What's Changed #### New Features * Add `__pydantic_on_complete__()` hook that is called once model is fully ready to be used by @DouweM in [#11762](https://github.com/pydantic/pydantic/pull/11762) * Add initial support for Python 3.14 by @Viicos in [#11991](https://github.com/pydantic/pydantic/pull/11991) * Add regex patterns to JSON schema for `Decimal` type by @Dima-Bulavenko in [#11987](https://github.com/pydantic/pydantic/pull/11987) * Add support for `doc` attribute on dataclass fields by @Viicos in [#12077](https://github.com/pydantic/pydantic/pull/12077) * Add experimental `MISSING` sentinel by @Viicos in [#11883](https://github.com/pydantic/pydantic/pull/11883) #### Changes * Allow config and bases to be specified together in `create_model()` by @Viicos in [#11714](https://github.com/pydantic/pydantic/pull/11714) * Move some field logic out of the `GenerateSchema` class by @Viicos in [#11733](https://github.com/pydantic/pydantic/pull/11733) * Always make use of `inspect.getsourcelines()` for docstring extraction on Python 3.13 and greater by @Viicos in [#11829](https://github.com/pydantic/pydantic/pull/11829) * Only support the latest Mypy version by @Viicos in [#11832](https://github.com/pydantic/pydantic/pull/11832) * Do not implicitly convert after model validators to class methods by @Viicos in [#11957](https://github.com/pydantic/pydantic/pull/11957) * Refactor `FieldInfo` creation implementation by @Viicos in [#11898](https://github.com/pydantic/pydantic/pull/11898) * Make `Secret` covariant by @bluenote10 in [#12008](https://github.com/pydantic/pydantic/pull/12008) * Emit warning when field-specific metadata is used in invalid contexts by @Viicos in [#12028](https://github.com/pydantic/pydantic/pull/12028) #### Fixes * Properly fetch plain serializer function when serializing default value in JSON Schema by @Viicos in [#11721](https://github.com/pydantic/pydantic/pull/11721) * Remove generics cache workaround by @Viicos in [#11755](https://github.com/pydantic/pydantic/pull/11755) * Remove coercion of decimal constraints by @Viicos in [#11772](https://github.com/pydantic/pydantic/pull/11772) * Fix crash when expanding root type in the mypy plugin by @Viicos in [#11735](https://github.com/pydantic/pydantic/pull/11735) * Only mark model as complete once all fields are complete by @DouweM in [#11759](https://github.com/pydantic/pydantic/pull/11759) * Do not provide `field_name` in validator core schemas by @DouweM in [#11761](https://github.com/pydantic/pydantic/pull/11761) * Fix issue with recursive generic models by @Viicos in [#11775](https://github.com/pydantic/pydantic/pull/11775) * Fix qualified name comparison of private attributes during namespace inspection by @karta9821 in [#11803](https://github.com/pydantic/pydantic/pull/11803) * Make sure Pydantic dataclasses with slots and `validate_assignment` can be unpickled by @Viicos in [#11769](https://github.com/pydantic/pydantic/pull/11769) * Traverse `function-before` schemas during schema gathering by @Viicos in [#11801](https://github.com/pydantic/pydantic/pull/11801) * Fix check for stdlib dataclasses by @Viicos in [#11822](https://github.com/pydantic/pydantic/pull/11822) * Check if `FieldInfo` is complete after applying type variable map by @Viicos in [#11855](https://github.com/pydantic/pydantic/pull/11855) * Do not delete mock validator/serializer in `model_rebuild()` by @Viicos in [#11890](https://github.com/pydantic/pydantic/pull/11890) * Rebuild dataclass fields before schema generation by @Viicos in [#11949](https://github.com/pydantic/pydantic/pull/11949) * Always store the original field assignment on `FieldInfo` by @Viicos in [#11946](https://github.com/pydantic/pydantic/pull/11946) * Do not use deprecated methods as default field values by @Viicos in [#11914](https://github.com/pydantic/pydantic/pull/11914) * Allow callable discriminator to be applied on PEP 695 type aliases by @Viicos in [#11941](https://github.com/pydantic/pydantic/pull/11941) * Suppress core schema generation warning when using `SkipValidation` by @ygsh0816 in [#12002](https://github.com/pydantic/pydantic/pull/12002) * Do not emit typechecking error for invalid `Field()` default with `validate_default` set to `True` by @Viicos in [#11988](https://github.com/pydantic/pydantic/pull/11988) * Refactor logic to support Pydantic's `Field()` function in dataclasses by @Viicos in [#12051](https://github.com/pydantic/pydantic/pull/12051) #### Packaging * Update project metadata to use PEP 639 by @Viicos in [#11694](https://github.com/pydantic/pydantic/pull/11694) * Bump `mkdocs-llmstxt` to v0.2.0 by @Viicos in [#11725](https://github.com/pydantic/pydantic/pull/11725) * Bump `pydantic-core` to v2.35.1 by @Viicos in [#11963](https://github.com/pydantic/pydantic/pull/11963) * Bump dawidd6/action-download-artifact from 10 to 11 by @dependabot[bot] in [#12033](https://github.com/pydantic/pydantic/pull/12033) * Bump astral-sh/setup-uv from 5 to 6 by @dependabot[bot] in [#11826](https://github.com/pydantic/pydantic/pull/11826) * Update mypy to 1.17.0 by @Viicos in [#12076](https://github.com/pydantic/pydantic/pull/12076) ### New Contributors * @parth-paradkar made their first contribution in [#11695](https://github.com/pydantic/pydantic/pull/11695) * @dqkqd made their first contribution in [#11739](https://github.com/pydantic/pydantic/pull/11739) * @fhightower made their first contribution in [#11722](https://github.com/pydantic/pydantic/pull/11722) * @gbaian10 made their first contribution in [#11766](https://github.com/pydantic/pydantic/pull/11766) * @DouweM made their first contribution in [#11759](https://github.com/pydantic/pydantic/pull/11759) * @bowenliang123 made their first contribution in [#11719](https://github.com/pydantic/pydantic/pull/11719) * @rawwar made their first contribution in [#11799](https://github.com/pydantic/pydantic/pull/11799) * @karta9821 made their first contribution in [#11803](https://github.com/pydantic/pydantic/pull/11803) * @jinnovation made their first contribution in [#11834](https://github.com/pydantic/pydantic/pull/11834) * @zmievsa made their first contribution in [#11861](https://github.com/pydantic/pydantic/pull/11861) * @Otto-AA made their first contribution in [#11860](https://github.com/pydantic/pydantic/pull/11860) * @ygsh0816 made their first contribution in [#12002](https://github.com/pydantic/pydantic/pull/12002) * @lukland made their first contribution in [#12015](https://github.com/pydantic/pydantic/pull/12015) * @Dima-Bulavenko made their first contribution in [#11987](https://github.com/pydantic/pydantic/pull/11987) * @GSemikozov made their first contribution in [#12050](https://github.com/pydantic/pydantic/pull/12050) * @hannah-heywa made their first contribution in [#12082](https://github.com/pydantic/pydantic/pull/12082) ## v2.11.10 (2025-10-04) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.10) ### What's Changed #### Fixes * Backport v1.10.24 changes by @Viicos ## v2.11.9 (2025-09-13) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.9) ### What's Changed #### Fixes * Backport v1.10.23 changes by @Viicos ## v2.11.8 (2025-09-13) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.8) ### What's Changed #### Fixes * Fix mypy plugin for mypy 1.18 by @cdce8p in [#12209](https://github.com/pydantic/pydantic/pull/12209) ## v2.11.7 (2025-06-14) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.7) ### What's Changed #### Fixes * Copy `FieldInfo` instance if necessary during `FieldInfo` build by @Viicos in [#11898](https://github.com/pydantic/pydantic/pull/11898) ## v2.11.6 (2025-06-13) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.6) ### What's Changed #### Fixes * Rebuild dataclass fields before schema generation by @Viicos in [#11949](https://github.com/pydantic/pydantic/pull/11949) * Always store the original field assignment on `FieldInfo` by @Viicos in [#11946](https://github.com/pydantic/pydantic/pull/11946) ## v2.11.5 (2025-05-22) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.5) ### What's Changed #### Fixes * Check if `FieldInfo` is complete after applying type variable map by @Viicos in [#11855](https://github.com/pydantic/pydantic/pull/11855) * Do not delete mock validator/serializer in `model_rebuild()` by @Viicos in [#11890](https://github.com/pydantic/pydantic/pull/11890) * Do not duplicate metadata on model rebuild by @Viicos in [#11902](https://github.com/pydantic/pydantic/pull/11902) ## v2.11.4 (2025-04-29) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.4) ### What's Changed #### Changes * Allow config and bases to be specified together in `create_model()` by @Viicos in [#11714](https://github.com/pydantic/pydantic/pull/11714). This change was backported as it was previously possible (although not meant to be supported) to provide `model_config` as a field, which would make it possible to provide both configuration and bases. #### Fixes * Remove generics cache workaround by @Viicos in [#11755](https://github.com/pydantic/pydantic/pull/11755) * Remove coercion of decimal constraints by @Viicos in [#11772](https://github.com/pydantic/pydantic/pull/11772) * Fix crash when expanding root type in the mypy plugin by @Viicos in [#11735](https://github.com/pydantic/pydantic/pull/11735) * Fix issue with recursive generic models by @Viicos in [#11775](https://github.com/pydantic/pydantic/pull/11775) * Traverse `function-before` schemas during schema gathering by @Viicos in [#11801](https://github.com/pydantic/pydantic/pull/11801) #### Packaging * Bump `mkdocs-llmstxt` to v0.2.0 by @Viicos in [#11725](https://github.com/pydantic/pydantic/pull/11725) ## v2.11.3 (2025-04-08) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.3) ### What's Changed #### Fixes * Preserve field description when rebuilding model fields by @Viicos in [#11698](https://github.com/pydantic/pydantic/pull/11698) #### Packaging * Update V1 copy to v1.10.21 by @Viicos in [#11706](https://github.com/pydantic/pydantic/pull/11706) ## v2.11.2 (2025-04-03) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.2) ### What's Changed #### Fixes * Bump `pydantic-core` to v2.33.1 by @Viicos in [#11678](https://github.com/pydantic/pydantic/pull/11678) * Make sure `__pydantic_private__` exists before setting private attributes by @Viicos in [#11666](https://github.com/pydantic/pydantic/pull/11666) * Do not override `FieldInfo._complete` when using field from parent class by @Viicos in [#11668](https://github.com/pydantic/pydantic/pull/11668) * Provide the available definitions when applying discriminated unions by @Viicos in [#11670](https://github.com/pydantic/pydantic/pull/11670) * Do not expand root type in the mypy plugin for variables by @Viicos in [#11676](https://github.com/pydantic/pydantic/pull/11676) * Mention the attribute name in model fields deprecation message by @Viicos in [#11674](https://github.com/pydantic/pydantic/pull/11674) * Properly validate parameterized mappings by @Viicos in [#11658](https://github.com/pydantic/pydantic/pull/11658) ## v2.11.1 (2025-03-28) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.1) ### What's Changed #### Fixes * Do not override `'definitions-ref'` schemas containing serialization schemas or metadata by @Viicos in [#11644](https://github.com/pydantic/pydantic/pull/11644) ## v2.11.0 (2025-03-27) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.0) ### What's Changed Pydantic v2.11 is a version strongly focused on build time performance of Pydantic models (and core schema generation in general). See the [blog post](https://pydantic.dev/articles/pydantic-v2-11-release) for more details. #### New Features * Add `encoded_string()` method to the URL types by @YassinNouh21 in [#11580](https://github.com/pydantic/pydantic/pull/11580) * Add support for `defer_build` with `@validate_call` decorator by @Viicos in [#11584](https://github.com/pydantic/pydantic/pull/11584) * Allow `@with_config` decorator to be used with keyword arguments by @Viicos in [#11608](https://github.com/pydantic/pydantic/pull/11608) * Simplify customization of default value inclusion in JSON Schema generation by @Viicos in [#11634](https://github.com/pydantic/pydantic/pull/11634) * Add `generate_arguments_schema()` function by @Viicos in [#11572](https://github.com/pydantic/pydantic/pull/11572) #### Fixes * Allow generic typed dictionaries to be used for unpacked variadic keyword parameters by @Viicos in [#11571](https://github.com/pydantic/pydantic/pull/11571) * Fix runtime error when computing model string representation involving cached properties and self-referenced models by @Viicos in [#11579](https://github.com/pydantic/pydantic/pull/11579) * Preserve other steps when using the ellipsis in the pipeline API by @Viicos in [#11626](https://github.com/pydantic/pydantic/pull/11626) * Fix deferred discriminator application logic by @Viicos in [#11591](https://github.com/pydantic/pydantic/pull/11591) #### Packaging * Bump `pydantic-core` to v2.33.0 by @Viicos in [#11631](https://github.com/pydantic/pydantic/pull/11631) ### New Contributors * @cmenon12 made their first contribution in [#11562](https://github.com/pydantic/pydantic/pull/11562) * @Jeukoh made their first contribution in [#11611](https://github.com/pydantic/pydantic/pull/11611) ## v2.11.0b2 (2025-03-17) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.0b2) ### What's Changed #### New Features * Add experimental support for free threading by @Viicos in [#11516](https://github.com/pydantic/pydantic/pull/11516) #### Fixes * Fix `NotRequired` qualifier not taken into account in stringified annotation by @Viicos in [#11559](https://github.com/pydantic/pydantic/pull/11559) #### Packaging * Bump `pydantic-core` to v2.32.0 by @Viicos in [#11567](https://github.com/pydantic/pydantic/pull/11567) ### New Contributors * @joren485 made their first contribution in [#11547](https://github.com/pydantic/pydantic/pull/11547) ## v2.11.0b1 (2025-03-06) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.0b1) ### What's Changed #### New Features * Support unsubstituted type variables with both a default and a bound or constraints by @FyZzyss in https://github.com/pydantic/pydantic/pull/10789 * Add a `default_factory_takes_validated_data` property to `FieldInfo` by @Viicos in https://github.com/pydantic/pydantic/pull/11034 * Raise a better error when a generic alias is used inside `type[]` by @Viicos in https://github.com/pydantic/pydantic/pull/11088 * Properly support PEP 695 generics syntax by @Viicos in https://github.com/pydantic/pydantic/pull/11189 * Properly support type variable defaults by @Viicos in https://github.com/pydantic/pydantic/pull/11332 * Add support for validating v6, v7, v8 UUIDs by @astei in https://github.com/pydantic/pydantic/pull/11436 * Improve alias configuration APIs by @sydney-runkle in https://github.com/pydantic/pydantic/pull/11468 #### Changes * Rework `create_model` field definitions format by @Viicos in https://github.com/pydantic/pydantic/pull/11032 * Raise a deprecation warning when a field is annotated as final with a default value by @Viicos in https://github.com/pydantic/pydantic/pull/11168 * Deprecate accessing `model_fields` and `model_computed_fields` on instances by @Viicos in https://github.com/pydantic/pydantic/pull/11169 * **Breaking Change:** Move core schema generation logic for path types inside the `GenerateSchema` class by @sydney-runkle in https://github.com/pydantic/pydantic/pull/10846 * Remove Python 3.8 Support by @sydney-runkle in https://github.com/pydantic/pydantic/pull/11258 * Optimize calls to `get_type_ref` by @Viicos in https://github.com/pydantic/pydantic/pull/10863 * Disable `pydantic-core` core schema validation by @sydney-runkle in https://github.com/pydantic/pydantic/pull/11271 #### Performance * Only evaluate `FieldInfo` annotations if required during schema building by @Viicos in https://github.com/pydantic/pydantic/pull/10769 * Improve `__setattr__` performance of Pydantic models by caching setter functions by @MarkusSintonen in https://github.com/pydantic/pydantic/pull/10868 * Improve annotation application performance by @Viicos in https://github.com/pydantic/pydantic/pull/11186 * Improve performance of `_typing_extra` module by @Viicos in https://github.com/pydantic/pydantic/pull/11255 * Refactor and optimize schema cleaning logic by @Viicos in https://github.com/pydantic/pydantic/pull/11244 * Create a single dictionary when creating a `CoreConfig` instance by @sydney-runkle in https://github.com/pydantic/pydantic/pull/11384 * Bump `pydantic-core` and thus use `SchemaValidator` and `SchemaSerializer` caching by @sydney-runkle in https://github.com/pydantic/pydantic/pull/11402 * Reuse cached core schemas for parametrized generic Pydantic models by @MarkusSintonen in https://github.com/pydantic/pydantic/pull/11434 #### Fixes * Improve `TypeAdapter` instance repr by @sydney-runkle in https://github.com/pydantic/pydantic/pull/10872 * Use the correct frame when instantiating a parametrized `TypeAdapter` by @Viicos in https://github.com/pydantic/pydantic/pull/10893 * Infer final fields with a default value as class variables in the mypy plugin by @Viicos in https://github.com/pydantic/pydantic/pull/11121 * Recursively unpack `Literal` values if using PEP 695 type aliases by @Viicos in https://github.com/pydantic/pydantic/pull/11114 * Override `__subclasscheck__` on `ModelMetaclass` to avoid memory leak and performance issues by @Viicos in https://github.com/pydantic/pydantic/pull/11116 * Remove unused `_extract_get_pydantic_json_schema()` parameter by @Viicos in https://github.com/pydantic/pydantic/pull/11155 * Improve discriminated union error message for invalid union variants by @Viicos in https://github.com/pydantic/pydantic/pull/11161 * Unpack PEP 695 type aliases if using the `Annotated` form by @Viicos in https://github.com/pydantic/pydantic/pull/11109 * Add missing stacklevel in `deprecated_instance_property` warning by @Viicos in https://github.com/pydantic/pydantic/pull/11200 * Copy `WithJsonSchema` schema to avoid sharing mutated data by @thejcannon in https://github.com/pydantic/pydantic/pull/11014 * Do not cache parametrized models when in the process of parametrizing another model by @Viicos in https://github.com/pydantic/pydantic/pull/10704 * Add discriminated union related metadata entries to the `CoreMetadata` definition by @Viicos in https://github.com/pydantic/pydantic/pull/11216 * Consolidate schema definitions logic in the `_Definitions` class by @Viicos in https://github.com/pydantic/pydantic/pull/11208 * Support initializing root model fields with values of the `root` type in the mypy plugin by @Viicos in https://github.com/pydantic/pydantic/pull/11212 * Fix various issues with dataclasses and `use_attribute_docstrings` by @Viicos in https://github.com/pydantic/pydantic/pull/11246 * Only compute normalized decimal places if necessary in `decimal_places_validator` by @misrasaurabh1 in https://github.com/pydantic/pydantic/pull/11281 * Add support for `validation_alias` in the mypy plugin by @Viicos in https://github.com/pydantic/pydantic/pull/11295 * Fix JSON Schema reference collection with `"examples"` keys by @Viicos in https://github.com/pydantic/pydantic/pull/11305 * Do not transform model serializer functions as class methods in the mypy plugin by @Viicos in https://github.com/pydantic/pydantic/pull/11298 * Simplify `GenerateJsonSchema.literal_schema()` implementation by @misrasaurabh1 in https://github.com/pydantic/pydantic/pull/11321 * Add additional allowed schemes for `ClickHouseDsn` by @Maze21127 in https://github.com/pydantic/pydantic/pull/11319 * Coerce decimal constraints to `Decimal` instances by @Viicos in https://github.com/pydantic/pydantic/pull/11350 * Use the correct JSON Schema mode when handling function schemas by @Viicos in https://github.com/pydantic/pydantic/pull/11367 * Improve exception message when encountering recursion errors during type evaluation by @Viicos in https://github.com/pydantic/pydantic/pull/11356 * Always include `additionalProperties: True` for arbitrary dictionary schemas by @austinyu in https://github.com/pydantic/pydantic/pull/11392 * Expose `fallback` parameter in serialization methods by @Viicos in https://github.com/pydantic/pydantic/pull/11398 * Fix path serialization behavior by @sydney-runkle in https://github.com/pydantic/pydantic/pull/11416 * Do not reuse validators and serializers during model rebuild by @Viicos in https://github.com/pydantic/pydantic/pull/11429 * Collect model fields when rebuilding a model by @Viicos in https://github.com/pydantic/pydantic/pull/11388 * Allow cached properties to be altered on frozen models by @Viicos in https://github.com/pydantic/pydantic/pull/11432 * Fix tuple serialization for `Sequence` types by @sydney-runkle in https://github.com/pydantic/pydantic/pull/11435 * Fix: do not check for `__get_validators__` on classes where `__get_pydantic_core_schema__` is also defined by @tlambert03 in https://github.com/pydantic/pydantic/pull/11444 * Allow callable instances to be used as serializers by @Viicos in https://github.com/pydantic/pydantic/pull/11451 * Improve error thrown when overriding field with a property by @sydney-runkle in https://github.com/pydantic/pydantic/pull/11459 * Fix JSON Schema generation with referenceable core schemas holding JSON metadata by @Viicos in https://github.com/pydantic/pydantic/pull/11475 * Support strict specification on union member types by @sydney-runkle in https://github.com/pydantic/pydantic/pull/11481 * Implicitly set `validate_by_name` to `True` when `validate_by_alias` is `False` by @sydney-runkle in https://github.com/pydantic/pydantic/pull/11503 * Change type of `Any` when synthesizing `BaseSettings.__init__` signature in the mypy plugin by @Viicos in https://github.com/pydantic/pydantic/pull/11497 * Support type variable defaults referencing other type variables by @Viicos in https://github.com/pydantic/pydantic/pull/11520 * Fix `ValueError` on year zero by @davidhewitt in https://github.com/pydantic/pydantic-core/pull/1583 * `dataclass` `InitVar` shouldn't be required on serialization by @sydney-runkle in https://github.com/pydantic/pydantic-core/pull/1602 #### Packaging * Add a `check_pydantic_core_version()` function by @Viicos in https://github.com/pydantic/pydantic/pull/11324 * Remove `greenlet` development dependency by @Viicos in https://github.com/pydantic/pydantic/pull/11351 * Use the `typing-inspection` library by @Viicos in https://github.com/pydantic/pydantic/pull/11479 * Bump `pydantic-core` to `v2.31.1` by @sydney-runkle in https://github.com/pydantic/pydantic/pull/11526 ## New Contributors * @FyZzyss made their first contribution in https://github.com/pydantic/pydantic/pull/10789 * @tamird made their first contribution in https://github.com/pydantic/pydantic/pull/10948 * @felixxm made their first contribution in https://github.com/pydantic/pydantic/pull/11077 * @alexprabhat99 made their first contribution in https://github.com/pydantic/pydantic/pull/11082 * @Kharianne made their first contribution in https://github.com/pydantic/pydantic/pull/11111 * @mdaffad made their first contribution in https://github.com/pydantic/pydantic/pull/11177 * @thejcannon made their first contribution in https://github.com/pydantic/pydantic/pull/11014 * @thomasfrimannkoren made their first contribution in https://github.com/pydantic/pydantic/pull/11251 * @usernameMAI made their first contribution in https://github.com/pydantic/pydantic/pull/11275 * @ananiavito made their first contribution in https://github.com/pydantic/pydantic/pull/11302 * @pawamoy made their first contribution in https://github.com/pydantic/pydantic/pull/11311 * @Maze21127 made their first contribution in https://github.com/pydantic/pydantic/pull/11319 * @kauabh made their first contribution in https://github.com/pydantic/pydantic/pull/11369 * @jaceklaskowski made their first contribution in https://github.com/pydantic/pydantic/pull/11353 * @tmpbeing made their first contribution in https://github.com/pydantic/pydantic/pull/11375 * @petyosi made their first contribution in https://github.com/pydantic/pydantic/pull/11405 * @austinyu made their first contribution in https://github.com/pydantic/pydantic/pull/11392 * @mikeedjones made their first contribution in https://github.com/pydantic/pydantic/pull/11402 * @astei made their first contribution in https://github.com/pydantic/pydantic/pull/11436 * @dsayling made their first contribution in https://github.com/pydantic/pydantic/pull/11522 * @sobolevn made their first contribution in https://github.com/pydantic/pydantic-core/pull/1645 ## v2.11.0a2 (2025-02-10) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.0a2) ### What's Changed Pydantic v2.11 is a version strongly focused on build time performance of Pydantic models (and core schema generation in general). This is another early alpha release, meant to collect early feedback from users having issues with core schema builds. #### Performance * Create a single dictionary when creating a `CoreConfig` instance by @sydney-runkle in [#11384](https://github.com/pydantic/pydantic/pull/11384) #### Fixes * Use the correct JSON Schema mode when handling function schemas by @Viicos in [#11367](https://github.com/pydantic/pydantic/pull/11367) * Fix JSON Schema reference logic with `examples` keys by @Viicos in [#11366](https://github.com/pydantic/pydantic/pull/11366) * Improve exception message when encountering recursion errors during type evaluation by @Viicos in [#11356](https://github.com/pydantic/pydantic/pull/11356) * Always include `additionalProperties: True` for arbitrary dictionary schemas by @austinyu in [#11392](https://github.com/pydantic/pydantic/pull/11392) * Expose `fallback` parameter in serialization methods by @Viicos in [#11398](https://github.com/pydantic/pydantic/pull/11398) * Fix path serialization behavior by @sydney-runkle in [#11416](https://github.com/pydantic/pydantic/pull/11416) #### Packaging * Bump `ruff` from 0.9.2 to 0.9.5 by @Viicos in [#11407](https://github.com/pydantic/pydantic/pull/11407) * Bump `pydantic-core` to v2.29.0 by @mikeedjones in [#11402](https://github.com/pydantic/pydantic/pull/11402) * Use locally-built rust with symbols & pgo by @davidhewitt in [#11403](https://github.com/pydantic/pydantic/pull/11403) ### New Contributors * @kauabh made their first contribution in [#11369](https://github.com/pydantic/pydantic/pull/11369) * @jaceklaskowski made their first contribution in [#11353](https://github.com/pydantic/pydantic/pull/11353) * @tmpbeing made their first contribution in [#11375](https://github.com/pydantic/pydantic/pull/11375) * @petyosi made their first contribution in [#11405](https://github.com/pydantic/pydantic/pull/11405) * @austinyu made their first contribution in [#11392](https://github.com/pydantic/pydantic/pull/11392) * @mikeedjones made their first contribution in [#11402](https://github.com/pydantic/pydantic/pull/11402) ## v2.11.0a1 (2025-01-30) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.0a1) ### What's Changed Pydantic v2.11 is a version strongly focused on build time performance of Pydantic models (and core schema generation in general). This is an early alpha release, meant to collect early feedback from users having issues with core schema builds. #### New Features * Support unsubstituted type variables with both a default and a bound or constraints by @FyZzyss in [#10789](https://github.com/pydantic/pydantic/pull/10789) * Add a `default_factory_takes_validated_data` property to `FieldInfo` by @Viicos in [#11034](https://github.com/pydantic/pydantic/pull/11034) * Raise a better error when a generic alias is used inside `type[]` by @Viicos in [#11088](https://github.com/pydantic/pydantic/pull/11088) * Properly support PEP 695 generics syntax by @Viicos in [#11189](https://github.com/pydantic/pydantic/pull/11189) * Properly support type variable defaults by @Viicos in [#11332](https://github.com/pydantic/pydantic/pull/11332) #### Changes * Rework `create_model` field definitions format by @Viicos in [#11032](https://github.com/pydantic/pydantic/pull/11032) * Raise a deprecation warning when a field is annotated as final with a default value by @Viicos in [#11168](https://github.com/pydantic/pydantic/pull/11168) * Deprecate accessing `model_fields` and `model_computed_fields` on instances by @Viicos in [#11169](https://github.com/pydantic/pydantic/pull/11169) * Move core schema generation logic for path types inside the `GenerateSchema` class by @sydney-runkle in [#10846](https://github.com/pydantic/pydantic/pull/10846) * Move `deque` schema gen to `GenerateSchema` class by @sydney-runkle in [#11239](https://github.com/pydantic/pydantic/pull/11239) * Move `Mapping` schema gen to `GenerateSchema` to complete removal of `prepare_annotations_for_known_type` workaround by @sydney-runkle in [#11247](https://github.com/pydantic/pydantic/pull/11247) * Remove Python 3.8 Support by @sydney-runkle in [#11258](https://github.com/pydantic/pydantic/pull/11258) * Disable `pydantic-core` core schema validation by @sydney-runkle in [#11271](https://github.com/pydantic/pydantic/pull/11271) #### Performance * Only evaluate `FieldInfo` annotations if required during schema building by @Viicos in [#10769](https://github.com/pydantic/pydantic/pull/10769) * Optimize calls to `get_type_ref` by @Viicos in [#10863](https://github.com/pydantic/pydantic/pull/10863) * Improve `__setattr__` performance of Pydantic models by caching setter functions by @MarkusSintonen in [#10868](https://github.com/pydantic/pydantic/pull/10868) * Improve annotation application performance by @Viicos in [#11186](https://github.com/pydantic/pydantic/pull/11186) * Improve performance of `_typing_extra` module by @Viicos in [#11255](https://github.com/pydantic/pydantic/pull/11255) * Refactor and optimize schema cleaning logic by @Viicos and @MarkusSintonen in [#11244](https://github.com/pydantic/pydantic/pull/11244) #### Fixes * Add validation tests for `_internal/_validators.py` by @tkasuz in [#10763](https://github.com/pydantic/pydantic/pull/10763) * Improve `TypeAdapter` instance repr by @sydney-runkle in [#10872](https://github.com/pydantic/pydantic/pull/10872) * Revert "ci: use locally built pydantic-core with debug symbols by @sydney-runkle in [#10942](https://github.com/pydantic/pydantic/pull/10942) * Re-enable all FastAPI tests by @tamird in [#10948](https://github.com/pydantic/pydantic/pull/10948) * Fix typo in HISTORY.md. by @felixxm in [#11077](https://github.com/pydantic/pydantic/pull/11077) * Infer final fields with a default value as class variables in the mypy plugin by @Viicos in [#11121](https://github.com/pydantic/pydantic/pull/11121) * Recursively unpack `Literal` values if using PEP 695 type aliases by @Viicos in [#11114](https://github.com/pydantic/pydantic/pull/11114) * Override `__subclasscheck__` on `ModelMetaclass` to avoid memory leak and performance issues by @Viicos in [#11116](https://github.com/pydantic/pydantic/pull/11116) * Remove unused `_extract_get_pydantic_json_schema()` parameter by @Viicos in [#11155](https://github.com/pydantic/pydantic/pull/11155) * Add FastAPI and SQLModel to third-party tests by @sydney-runkle in [#11044](https://github.com/pydantic/pydantic/pull/11044) * Fix conditional expressions syntax for third-party tests by @Viicos in [#11162](https://github.com/pydantic/pydantic/pull/11162) * Move FastAPI tests to third-party workflow by @Viicos in [#11164](https://github.com/pydantic/pydantic/pull/11164) * Improve discriminated union error message for invalid union variants by @Viicos in [#11161](https://github.com/pydantic/pydantic/pull/11161) * Unpack PEP 695 type aliases if using the `Annotated` form by @Viicos in [#11109](https://github.com/pydantic/pydantic/pull/11109) * Include `openapi-python-client` check in issue creation for third-party failures, use `main` branch by @sydney-runkle in [#11182](https://github.com/pydantic/pydantic/pull/11182) * Add pandera third-party tests by @Viicos in [#11193](https://github.com/pydantic/pydantic/pull/11193) * Add ODMantic third-party tests by @sydney-runkle in [#11197](https://github.com/pydantic/pydantic/pull/11197) * Add missing stacklevel in `deprecated_instance_property` warning by @Viicos in [#11200](https://github.com/pydantic/pydantic/pull/11200) * Copy `WithJsonSchema` schema to avoid sharing mutated data by @thejcannon in [#11014](https://github.com/pydantic/pydantic/pull/11014) * Do not cache parametrized models when in the process of parametrizing another model by @Viicos in [#10704](https://github.com/pydantic/pydantic/pull/10704) * Re-enable Beanie third-party tests by @Viicos in [#11214](https://github.com/pydantic/pydantic/pull/11214) * Add discriminated union related metadata entries to the `CoreMetadata` definition by @Viicos in [#11216](https://github.com/pydantic/pydantic/pull/11216) * Consolidate schema definitions logic in the `_Definitions` class by @Viicos in [#11208](https://github.com/pydantic/pydantic/pull/11208) * Support initializing root model fields with values of the `root` type in the mypy plugin by @Viicos in [#11212](https://github.com/pydantic/pydantic/pull/11212) * Fix various issues with dataclasses and `use_attribute_docstrings` by @Viicos in [#11246](https://github.com/pydantic/pydantic/pull/11246) * Only compute normalized decimal places if necessary in `decimal_places_validator` by @misrasaurabh1 in [#11281](https://github.com/pydantic/pydantic/pull/11281) * Fix two misplaced sentences in validation errors documentation by @ananiavito in [#11302](https://github.com/pydantic/pydantic/pull/11302) * Fix mkdocstrings inventory example in documentation by @pawamoy in [#11311](https://github.com/pydantic/pydantic/pull/11311) * Add support for `validation_alias` in the mypy plugin by @Viicos in [#11295](https://github.com/pydantic/pydantic/pull/11295) * Do not transform model serializer functions as class methods in the mypy plugin by @Viicos in [#11298](https://github.com/pydantic/pydantic/pull/11298) * Simplify `GenerateJsonSchema.literal_schema()` implementation by @misrasaurabh1 in [#11321](https://github.com/pydantic/pydantic/pull/11321) * Add additional allowed schemes for `ClickHouseDsn` by @Maze21127 in [#11319](https://github.com/pydantic/pydantic/pull/11319) * Coerce decimal constraints to `Decimal` instances by @Viicos in [#11350](https://github.com/pydantic/pydantic/pull/11350) * Fix `ValueError` on year zero by @davidhewitt in [pydantic-core#1583](https://github.com/pydantic/pydantic-core/pull/1583) #### Packaging * Bump dawidd6/action-download-artifact from 6 to 7 by @dependabot in [#11018](https://github.com/pydantic/pydantic/pull/11018) * Re-enable memray related tests on Python 3.12+ by @Viicos in [#11191](https://github.com/pydantic/pydantic/pull/11191) * Bump astral-sh/setup-uv to 5 by @dependabot in [#11205](https://github.com/pydantic/pydantic/pull/11205) * Bump `ruff` to v0.9.0 by @sydney-runkle in [#11254](https://github.com/pydantic/pydantic/pull/11254) * Regular `uv.lock` deps update by @sydney-runkle in [#11333](https://github.com/pydantic/pydantic/pull/11333) * Add a `check_pydantic_core_version()` function by @Viicos in [#11324](https://github.com/pydantic/pydantic/pull/11324) * Remove `greenlet` development dependency by @Viicos in [#11351](https://github.com/pydantic/pydantic/pull/11351) * Bump `pydantic-core` to v2.28.0 by @Viicos in [#11364](https://github.com/pydantic/pydantic/pull/11364) ### New Contributors * @FyZzyss made their first contribution in [#10789](https://github.com/pydantic/pydantic/pull/10789) * @tamird made their first contribution in [#10948](https://github.com/pydantic/pydantic/pull/10948) * @felixxm made their first contribution in [#11077](https://github.com/pydantic/pydantic/pull/11077) * @alexprabhat99 made their first contribution in [#11082](https://github.com/pydantic/pydantic/pull/11082) * @Kharianne made their first contribution in [#11111](https://github.com/pydantic/pydantic/pull/11111) * @mdaffad made their first contribution in [#11177](https://github.com/pydantic/pydantic/pull/11177) * @thejcannon made their first contribution in [#11014](https://github.com/pydantic/pydantic/pull/11014) * @thomasfrimannkoren made their first contribution in [#11251](https://github.com/pydantic/pydantic/pull/11251) * @usernameMAI made their first contribution in [#11275](https://github.com/pydantic/pydantic/pull/11275) * @ananiavito made their first contribution in [#11302](https://github.com/pydantic/pydantic/pull/11302) * @pawamoy made their first contribution in [#11311](https://github.com/pydantic/pydantic/pull/11311) * @Maze21127 made their first contribution in [#11319](https://github.com/pydantic/pydantic/pull/11319) ## v2.10.6 (2025-01-23) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.10.6) ### What's Changed #### Fixes * Fix JSON Schema reference collection with `'examples'` keys by @Viicos in [#11325](https://github.com/pydantic/pydantic/pull/11325) * Fix url python serialization by @sydney-runkle in [#11331](https://github.com/pydantic/pydantic/pull/11331) ## v2.10.5 (2025-01-08) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.10.5) ### What's Changed #### Fixes * Remove custom MRO implementation of Pydantic models by @Viicos in [#11184](https://github.com/pydantic/pydantic/pull/11184) * Fix URL serialization for unions by @sydney-runkle in [#11233](https://github.com/pydantic/pydantic/pull/11233) ## v2.10.4 (2024-12-18) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.10.4) ### What's Changed #### Fixes * Fix for comparison of `AnyUrl` objects by @alexprabhat99 in [#11082](https://github.com/pydantic/pydantic/pull/11082) * Properly fetch PEP 695 type params for functions, do not fetch annotations from signature by @Viicos in [#11093](https://github.com/pydantic/pydantic/pull/11093) * Include JSON Schema input core schema in function schemas by @Viicos in [#11085](https://github.com/pydantic/pydantic/pull/11085) * Add `len` to `_BaseUrl` to avoid TypeError by @Kharianne in [#11111](https://github.com/pydantic/pydantic/pull/11111) * Make sure the type reference is removed from the seen references by @Viicos in [#11143](https://github.com/pydantic/pydantic/pull/11143) ### New Contributors * @FyZzyss made their first contribution in [#10789](https://github.com/pydantic/pydantic/pull/10789) * @tamird made their first contribution in [#10948](https://github.com/pydantic/pydantic/pull/10948) * @felixxm made their first contribution in [#11077](https://github.com/pydantic/pydantic/pull/11077) * @alexprabhat99 made their first contribution in [#11082](https://github.com/pydantic/pydantic/pull/11082) * @Kharianne made their first contribution in [#11111](https://github.com/pydantic/pydantic/pull/11111) #### Packaging * Bump `pydantic-core` to v2.27.2 by @davidhewitt in [#11138](https://github.com/pydantic/pydantic/pull/11138) ## v2.10.3 (2024-12-03) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.10.3) ### What's Changed #### Fixes * Set fields when `defer_build` is set on Pydantic dataclasses by @Viicos in [#10984](https://github.com/pydantic/pydantic/pull/10984) * Do not resolve the JSON Schema reference for `dict` core schema keys by @Viicos in [#10989](https://github.com/pydantic/pydantic/pull/10989) * Use the globals of the function when evaluating the return type for `PlainSerializer` and `WrapSerializer` functions by @Viicos in [#11008](https://github.com/pydantic/pydantic/pull/11008) * Fix host required enforcement for urls to be compatible with v2.9 behavior by @sydney-runkle in [#11027](https://github.com/pydantic/pydantic/pull/11027) * Add a `default_factory_takes_validated_data` property to `FieldInfo` by @Viicos in [#11034](https://github.com/pydantic/pydantic/pull/11034) * Fix url json schema in `serialization` mode by @sydney-runkle in [#11035](https://github.com/pydantic/pydantic/pull/11035) ## v2.10.2 (2024-11-25) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.10.2) ### What's Changed #### Fixes * Only evaluate FieldInfo annotations if required during schema building by @Viicos in [#10769](https://github.com/pydantic/pydantic/pull/10769) * Do not evaluate annotations for private fields by @Viicos in [#10962](https://github.com/pydantic/pydantic/pull/10962) * Support serialization as any for `Secret` types and `Url` types by @sydney-runkle in [#10947](https://github.com/pydantic/pydantic/pull/10947) * Fix type hint of `Field.default` to be compatible with Python 3.8 and 3.9 by @Viicos in [#10972](https://github.com/pydantic/pydantic/pull/10972) * Add hashing support for URL types by @sydney-runkle in [#10975](https://github.com/pydantic/pydantic/pull/10975) * Hide `BaseModel.__replace__` definition from type checkers by @Viicos in [#10979](https://github.com/pydantic/pydantic/pull/10979) ## v2.10.1 (2024-11-21) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.10.1) ### What's Changed #### Fixes * Use the correct frame when instantiating a parametrized `TypeAdapter` by @Viicos in [#10893](https://github.com/pydantic/pydantic/pull/10893) * Relax check for validated data in `default_factory` utils by @sydney-runkle in [#10909](https://github.com/pydantic/pydantic/pull/10909) * Fix type checking issue with `model_fields` and `model_computed_fields` by @sydney-runkle in [#10911](https://github.com/pydantic/pydantic/pull/10911) * Use the parent configuration during schema generation for stdlib `dataclass`es by @sydney-runkle in [#10928](https://github.com/pydantic/pydantic/pull/10928) * Use the `globals` of the function when evaluating the return type of serializers and `computed_field`s by @Viicos in [#10929](https://github.com/pydantic/pydantic/pull/10929) * Fix URL constraint application by @sydney-runkle in [#10922](https://github.com/pydantic/pydantic/pull/10922) * Fix URL equality with different validation methods by @sydney-runkle in [#10934](https://github.com/pydantic/pydantic/pull/10934) * Fix JSON schema title when specified as `''` by @sydney-runkle in [#10936](https://github.com/pydantic/pydantic/pull/10936) * Fix `python` mode serialization for `complex` inference by @sydney-runkle in [pydantic-core#1549](https://github.com/pydantic/pydantic-core/pull/1549) #### Packaging * Bump `pydantic-core` version to `v2.27.1` by @sydney-runkle in [#10938](https://github.com/pydantic/pydantic/pull/10938) ### New Contributors ## v2.10.0 (2024-11-20) The code released in v2.10.0 is practically identical to that of v2.10.0b2. [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.10.0) See the [v2.10 release blog post](https://pydantic.dev/articles/pydantic-v2-10-release) for the highlights! ### What's Changed #### New Features * Support `fractions.Fraction` by @sydney-runkle in [#10318](https://github.com/pydantic/pydantic/pull/10318) * Support `Hashable` for json validation by @sydney-runkle in [#10324](https://github.com/pydantic/pydantic/pull/10324) * Add a `SocketPath` type for `linux` systems by @theunkn0wn1 in [#10378](https://github.com/pydantic/pydantic/pull/10378) * Allow arbitrary refs in JSON schema `examples` by @sydney-runkle in [#10417](https://github.com/pydantic/pydantic/pull/10417) * Support `defer_build` for Pydantic dataclasses by @Viicos in [#10313](https://github.com/pydantic/pydantic/pull/10313) * Adding v1 / v2 incompatibility warning for nested v1 model by @sydney-runkle in [#10431](https://github.com/pydantic/pydantic/pull/10431) * Add support for unpacked `TypedDict` to type hint variadic keyword arguments with `@validate_call` by @Viicos in [#10416](https://github.com/pydantic/pydantic/pull/10416) * Support compiled patterns in `protected_namespaces` by @sydney-runkle in [#10522](https://github.com/pydantic/pydantic/pull/10522) * Add support for `propertyNames` in JSON schema by @FlorianSW in [#10478](https://github.com/pydantic/pydantic/pull/10478) * Adding `__replace__` protocol for Python 3.13+ support by @sydney-runkle in [#10596](https://github.com/pydantic/pydantic/pull/10596) * Expose public `sort` method for JSON schema generation by @sydney-runkle in [#10595](https://github.com/pydantic/pydantic/pull/10595) * Add runtime validation of `@validate_call` callable argument by @kc0506 in [#10627](https://github.com/pydantic/pydantic/pull/10627) * Add `experimental_allow_partial` support by @samuelcolvin in [#10748](https://github.com/pydantic/pydantic/pull/10748) * Support default factories taking validated data as an argument by @Viicos in [#10678](https://github.com/pydantic/pydantic/pull/10678) * Allow subclassing `ValidationError` and `PydanticCustomError` by @Youssefares in [pydantic/pydantic-core#1413](https://github.com/pydantic/pydantic-core/pull/1413) * Add `trailing-strings` support to `experimental_allow_partial` by @sydney-runkle in [#10825](https://github.com/pydantic/pydantic/pull/10825) * Add `rebuild()` method for `TypeAdapter` and simplify `defer_build` patterns by @sydney-runkle in [#10537](https://github.com/pydantic/pydantic/pull/10537) * Improve `TypeAdapter` instance repr by @sydney-runkle in [#10872](https://github.com/pydantic/pydantic/pull/10872) #### Changes * Don't allow customization of `SchemaGenerator` until interface is more stable by @sydney-runkle in [#10303](https://github.com/pydantic/pydantic/pull/10303) * Cleanly `defer_build` on `TypeAdapters`, removing experimental flag by @sydney-runkle in [#10329](https://github.com/pydantic/pydantic/pull/10329) * Fix `mro` of generic subclass by @kc0506 in [#10100](https://github.com/pydantic/pydantic/pull/10100) * Strip whitespaces on JSON Schema title generation by @sydney-runkle in [#10404](https://github.com/pydantic/pydantic/pull/10404) * Use `b64decode` and `b64encode` for `Base64Bytes` type by @sydney-runkle in [#10486](https://github.com/pydantic/pydantic/pull/10486) * Relax protected namespace config default by @sydney-runkle in [#10441](https://github.com/pydantic/pydantic/pull/10441) * Revalidate parametrized generics if instance's origin is subclass of OG class by @sydney-runkle in [#10666](https://github.com/pydantic/pydantic/pull/10666) * Warn if configuration is specified on the `@dataclass` decorator and with the `__pydantic_config__` attribute by @sydney-runkle in [#10406](https://github.com/pydantic/pydantic/pull/10406) * Recommend against using `Ellipsis` (...) with `Field` by @Viicos in [#10661](https://github.com/pydantic/pydantic/pull/10661) * Migrate to subclassing instead of annotated approach for pydantic url types by @sydney-runkle in [#10662](https://github.com/pydantic/pydantic/pull/10662) * Change JSON schema generation of `Literal`s and `Enums` by @Viicos in [#10692](https://github.com/pydantic/pydantic/pull/10692) * Simplify unions involving `Any` or `Never` when replacing type variables by @Viicos in [#10338](https://github.com/pydantic/pydantic/pull/10338) * Do not require padding when decoding `base64` bytes by @bschoenmaeckers in [pydantic/pydantic-core#1448](https://github.com/pydantic/pydantic-core/pull/1448) * Support dates all the way to 1BC by @changhc in [pydantic/speedate#77](https://github.com/pydantic/speedate/pull/77) #### Performance * Schema cleaning: skip unnecessary copies during schema walking by @Viicos in [#10286](https://github.com/pydantic/pydantic/pull/10286) * Refactor namespace logic for annotations evaluation by @Viicos in [#10530](https://github.com/pydantic/pydantic/pull/10530) * Improve email regexp on edge cases by @AlekseyLobanov in [#10601](https://github.com/pydantic/pydantic/pull/10601) * `CoreMetadata` refactor with an emphasis on documentation, schema build time performance, and reducing complexity by @sydney-runkle in [#10675](https://github.com/pydantic/pydantic/pull/10675) #### Packaging * Bump `pydantic-core` to `v2.27.0` by @sydney-runkle in [#10825](https://github.com/pydantic/pydantic/pull/10825) * Replaced pdm with uv by @frfahim in [#10727](https://github.com/pydantic/pydantic/pull/10727) #### Fixes * Remove guarding check on `computed_field` with `field_serializer` by @nix010 in [#10390](https://github.com/pydantic/pydantic/pull/10390) * Fix `Predicate` issue in `v2.9.0` by @sydney-runkle in [#10321](https://github.com/pydantic/pydantic/pull/10321) * Fixing `annotated-types` bound by @sydney-runkle in [#10327](https://github.com/pydantic/pydantic/pull/10327) * Turn `tzdata` install requirement into optional `timezone` dependency by @jakob-keller in [#10331](https://github.com/pydantic/pydantic/pull/10331) * Use correct types namespace when building `namedtuple` core schemas by @Viicos in [#10337](https://github.com/pydantic/pydantic/pull/10337) * Fix evaluation of stringified annotations during namespace inspection by @Viicos in [#10347](https://github.com/pydantic/pydantic/pull/10347) * Fix `IncEx` type alias definition by @Viicos in [#10339](https://github.com/pydantic/pydantic/pull/10339) * Do not error when trying to evaluate annotations of private attributes by @Viicos in [#10358](https://github.com/pydantic/pydantic/pull/10358) * Fix nested type statement by @kc0506 in [#10369](https://github.com/pydantic/pydantic/pull/10369) * Improve typing of `ModelMetaclass.mro` by @Viicos in [#10372](https://github.com/pydantic/pydantic/pull/10372) * Fix class access of deprecated `computed_field`s by @Viicos in [#10391](https://github.com/pydantic/pydantic/pull/10391) * Make sure `inspect.iscoroutinefunction` works on coroutines decorated with `@validate_call` by @MovisLi in [#10374](https://github.com/pydantic/pydantic/pull/10374) * Fix `NameError` when using `validate_call` with PEP 695 on a class by @kc0506 in [#10380](https://github.com/pydantic/pydantic/pull/10380) * Fix `ZoneInfo` with various invalid types by @sydney-runkle in [#10408](https://github.com/pydantic/pydantic/pull/10408) * Fix `PydanticUserError` on empty `model_config` with annotations by @cdwilson in [#10412](https://github.com/pydantic/pydantic/pull/10412) * Fix variance issue in `_IncEx` type alias, only allow `True` by @Viicos in [#10414](https://github.com/pydantic/pydantic/pull/10414) * Fix serialization schema generation when using `PlainValidator` by @Viicos in [#10427](https://github.com/pydantic/pydantic/pull/10427) * Fix schema generation error when serialization schema holds references by @Viicos in [#10444](https://github.com/pydantic/pydantic/pull/10444) * Inline references if possible when generating schema for `json_schema_input_type` by @Viicos in [#10439](https://github.com/pydantic/pydantic/pull/10439) * Fix recursive arguments in `Representation` by @Viicos in [#10480](https://github.com/pydantic/pydantic/pull/10480) * Fix representation for builtin function types by @kschwab in [#10479](https://github.com/pydantic/pydantic/pull/10479) * Add python validators for decimal constraints (`max_digits` and `decimal_places`) by @sydney-runkle in [#10506](https://github.com/pydantic/pydantic/pull/10506) * Only fetch `__pydantic_core_schema__` from the current class during schema generation by @Viicos in [#10518](https://github.com/pydantic/pydantic/pull/10518) * Fix `stacklevel` on deprecation warnings for `BaseModel` by @sydney-runkle in [#10520](https://github.com/pydantic/pydantic/pull/10520) * Fix warning `stacklevel` in `BaseModel.__init__` by @Viicos in [#10526](https://github.com/pydantic/pydantic/pull/10526) * Improve error handling for in-evaluable refs for discriminator application by @sydney-runkle in [#10440](https://github.com/pydantic/pydantic/pull/10440) * Change the signature of `ConfigWrapper.core_config` to take the title directly by @Viicos in [#10562](https://github.com/pydantic/pydantic/pull/10562) * Do not use the previous config from the stack for dataclasses without config by @Viicos in [#10576](https://github.com/pydantic/pydantic/pull/10576) * Fix serialization for IP types with `mode='python'` by @sydney-runkle in [#10594](https://github.com/pydantic/pydantic/pull/10594) * Support constraint application for `Base64Etc` types by @sydney-runkle in [#10584](https://github.com/pydantic/pydantic/pull/10584) * Fix `validate_call` ignoring `Field` in `Annotated` by @kc0506 in [#10610](https://github.com/pydantic/pydantic/pull/10610) * Raise an error when `Self` is invalid by @kc0506 in [#10609](https://github.com/pydantic/pydantic/pull/10609) * Using `core_schema.InvalidSchema` instead of metadata injection + checks by @sydney-runkle in [#10523](https://github.com/pydantic/pydantic/pull/10523) * Tweak type alias logic by @kc0506 in [#10643](https://github.com/pydantic/pydantic/pull/10643) * Support usage of `type` with `typing.Self` and type aliases by @kc0506 in [#10621](https://github.com/pydantic/pydantic/pull/10621) * Use overloads for `Field` and `PrivateAttr` functions by @Viicos in [#10651](https://github.com/pydantic/pydantic/pull/10651) * Clean up the `mypy` plugin implementation by @Viicos in [#10669](https://github.com/pydantic/pydantic/pull/10669) * Properly check for `typing_extensions` variant of `TypeAliasType` by @Daraan in [#10713](https://github.com/pydantic/pydantic/pull/10713) * Allow any mapping in `BaseModel.model_copy()` by @Viicos in [#10751](https://github.com/pydantic/pydantic/pull/10751) * Fix `isinstance` behavior for urls by @sydney-runkle in [#10766](https://github.com/pydantic/pydantic/pull/10766) * Ensure `cached_property` can be set on Pydantic models by @Viicos in [#10774](https://github.com/pydantic/pydantic/pull/10774) * Fix equality checks for primitives in literals by @sydney-runkle in [pydantic/pydantic-core#1459](https://github.com/pydantic/pydantic-core/pull/1459) * Properly enforce `host_required` for URLs by @Viicos in [pydantic/pydantic-core#1488](https://github.com/pydantic/pydantic-core/pull/1488) * Fix when `coerce_numbers_to_str` enabled and string has invalid Unicode character by @andrey-berenda in [pydantic/pydantic-core#1515](https://github.com/pydantic/pydantic-core/pull/1515) * Fix serializing `complex` values in `Enum`s by @changhc in [pydantic/pydantic-core#1524](https://github.com/pydantic/pydantic-core/pull/1524) * Refactor `_typing_extra` module by @Viicos in [#10725](https://github.com/pydantic/pydantic/pull/10725) * Support intuitive equality for urls by @sydney-runkle in [#10798](https://github.com/pydantic/pydantic/pull/10798) * Add `bytearray` to `TypeAdapter.validate_json` signature by @samuelcolvin in [#10802](https://github.com/pydantic/pydantic/pull/10802) * Ensure class access of method descriptors is performed when used as a default with `Field` by @Viicos in [#10816](https://github.com/pydantic/pydantic/pull/10816) * Fix circular import with `validate_call` by @sydney-runkle in [#10807](https://github.com/pydantic/pydantic/pull/10807) * Fix error when using type aliases referencing other type aliases by @Viicos in [#10809](https://github.com/pydantic/pydantic/pull/10809) * Fix `IncEx` type alias to be compatible with mypy by @Viicos in [#10813](https://github.com/pydantic/pydantic/pull/10813) * Make `__signature__` a lazy property, do not deepcopy defaults by @Viicos in [#10818](https://github.com/pydantic/pydantic/pull/10818) * Make `__signature__` lazy for dataclasses, too by @sydney-runkle in [#10832](https://github.com/pydantic/pydantic/pull/10832) * Subclass all single host url classes from `AnyUrl` to preserve behavior from v2.9 by @sydney-runkle in [#10856](https://github.com/pydantic/pydantic/pull/10856) ### New Contributors * @jakob-keller made their first contribution in [#10331](https://github.com/pydantic/pydantic/pull/10331) * @MovisLi made their first contribution in [#10374](https://github.com/pydantic/pydantic/pull/10374) * @joaopalmeiro made their first contribution in [#10405](https://github.com/pydantic/pydantic/pull/10405) * @theunkn0wn1 made their first contribution in [#10378](https://github.com/pydantic/pydantic/pull/10378) * @cdwilson made their first contribution in [#10412](https://github.com/pydantic/pydantic/pull/10412) * @dlax made their first contribution in [#10421](https://github.com/pydantic/pydantic/pull/10421) * @kschwab made their first contribution in [#10479](https://github.com/pydantic/pydantic/pull/10479) * @santibreo made their first contribution in [#10453](https://github.com/pydantic/pydantic/pull/10453) * @FlorianSW made their first contribution in [#10478](https://github.com/pydantic/pydantic/pull/10478) * @tkasuz made their first contribution in [#10555](https://github.com/pydantic/pydantic/pull/10555) * @AlekseyLobanov made their first contribution in [#10601](https://github.com/pydantic/pydantic/pull/10601) * @NiclasvanEyk made their first contribution in [#10667](https://github.com/pydantic/pydantic/pull/10667) * @mschoettle made their first contribution in [#10677](https://github.com/pydantic/pydantic/pull/10677) * @Daraan made their first contribution in [#10713](https://github.com/pydantic/pydantic/pull/10713) * @k4nar made their first contribution in [#10736](https://github.com/pydantic/pydantic/pull/10736) * @UriyaHarpeness made their first contribution in [#10740](https://github.com/pydantic/pydantic/pull/10740) * @frfahim made their first contribution in [#10727](https://github.com/pydantic/pydantic/pull/10727) ## v2.10.0b2 (2024-11-13) Pre-release, see [the GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.10.0b2) for details. ## v2.10.0b1 (2024-11-06) Pre-release, see [the GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.10.0b1) for details. ## v2.9.2 (2024-09-17) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.9.2) ### What's Changed #### Fixes * Do not error when trying to evaluate annotations of private attributes by @Viicos in [#10358](https://github.com/pydantic/pydantic/pull/10358) * Adding notes on designing sound `Callable` discriminators by @sydney-runkle in [#10400](https://github.com/pydantic/pydantic/pull/10400) * Fix serialization schema generation when using `PlainValidator` by @Viicos in [#10427](https://github.com/pydantic/pydantic/pull/10427) * Fix `Union` serialization warnings by @sydney-runkle in [pydantic/pydantic-core#1449](https://github.com/pydantic/pydantic-core/pull/1449) * Fix variance issue in `_IncEx` type alias, only allow `True` by @Viicos in [#10414](https://github.com/pydantic/pydantic/pull/10414) * Fix `ZoneInfo` validation with various invalid types by @sydney-runkle in [#10408](https://github.com/pydantic/pydantic/pull/10408) ## v2.9.1 (2024-09-09) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.9.1) ### What's Changed #### Fixes * Fix Predicate issue in v2.9.0 by @sydney-runkle in [#10321](https://github.com/pydantic/pydantic/pull/10321) * Fixing `annotated-types` bound to `>=0.6.0` by @sydney-runkle in [#10327](https://github.com/pydantic/pydantic/pull/10327) * Turn `tzdata` install requirement into optional `timezone` dependency by @jakob-keller in [#10331](https://github.com/pydantic/pydantic/pull/10331) * Fix `IncExc` type alias definition by @Viicos in [#10339](https://github.com/pydantic/pydantic/pull/10339) * Use correct types namespace when building namedtuple core schemas by @Viicos in [#10337](https://github.com/pydantic/pydantic/pull/10337) * Fix evaluation of stringified annotations during namespace inspection by @Viicos in [#10347](https://github.com/pydantic/pydantic/pull/10347) * Fix tagged union serialization with alias generators by @sydney-runkle in [pydantic/pydantic-core#1442](https://github.com/pydantic/pydantic-core/pull/1442) ## v2.9.0 (2024-09-05) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.9.0) The code released in v2.9.0 is practically identical to that of v2.9.0b2. ### What's Changed #### New Features * Add support for `ZoneInfo` by @Youssefares in [#9896](https://github.com/pydantic/pydantic/pull/9896) * Add `Config.val_json_bytes` by @josh-newman in [#9770](https://github.com/pydantic/pydantic/pull/9770) * Add DSN for Snowflake by @aditkumar72 in [#10128](https://github.com/pydantic/pydantic/pull/10128) * Support `complex` number by @changhc in [#9654](https://github.com/pydantic/pydantic/pull/9654) * Add support for `annotated_types.Not` by @aditkumar72 in [#10210](https://github.com/pydantic/pydantic/pull/10210) * Allow `WithJsonSchema` to inject `$ref`s w/ `http` or `https` links by @dAIsySHEng1 in [#9863](https://github.com/pydantic/pydantic/pull/9863) * Allow validators to customize validation JSON schema by @Viicos in [#10094](https://github.com/pydantic/pydantic/pull/10094) * Support parametrized `PathLike` types by @nix010 in [#9764](https://github.com/pydantic/pydantic/pull/9764) * Add tagged union serializer that attempts to use `str` or `callable` discriminators to select the correct serializer by @sydney-runkle in in [pydantic/pydantic-core#1397](https://github.com/pydantic/pydantic-core/pull/1397) #### Changes * Breaking Change: Merge `dict` type `json_schema_extra` by @sydney-runkle in [#9792](https://github.com/pydantic/pydantic/pull/9792) * For more info (how to replicate old behavior) on this change, see [here](https://docs.pydantic.dev/dev/concepts/json_schema/#merging-json_schema_extra) * Refactor annotation injection for known (often generic) types by @sydney-runkle in [#9979](https://github.com/pydantic/pydantic/pull/9979) * Move annotation compatibility errors to validation phase by @sydney-runkle in [#9999](https://github.com/pydantic/pydantic/pull/9999) * Improve runtime errors for string constraints like `pattern` for incompatible types by @sydney-runkle in [#10158](https://github.com/pydantic/pydantic/pull/10158) * Remove `'allOf'` JSON schema workarounds by @dpeachey in [#10029](https://github.com/pydantic/pydantic/pull/10029) * Remove `typed_dict_cls` data from `CoreMetadata` by @sydney-runkle in [#10180](https://github.com/pydantic/pydantic/pull/10180) * Deprecate passing a dict to the `Examples` class by @Viicos in [#10181](https://github.com/pydantic/pydantic/pull/10181) * Remove `initial_metadata` from internal metadata construct by @sydney-runkle in [#10194](https://github.com/pydantic/pydantic/pull/10194) * Use `re.Pattern.search` instead of `re.Pattern.match` for consistency with `rust` behavior by @tinez in [pydantic/pydantic-core#1368](https://github.com/pydantic/pydantic-core/pull/1368) * Show value of wrongly typed data in `pydantic-core` serialization warning by @BoxyUwU in [pydantic/pydantic-core#1377](https://github.com/pydantic/pydantic-core/pull/1377) * Breaking Change: in `pydantic-core`, change `metadata` type hint in core schemas from `Any` -> `Dict[str, Any] | None` by @sydney-runkle in [pydantic/pydantic-core#1411](https://github.com/pydantic/pydantic-core/pull/1411) * Raise helpful warning when `self` isn't returned from model validator by @sydney-runkle in [#10255](https://github.com/pydantic/pydantic/pull/10255) #### Performance * Initial start at improving import times for modules, using caching primarily by @sydney-runkle in [#10009](https://github.com/pydantic/pydantic/pull/10009) * Using cached internal import for `BaseModel` by @sydney-runkle in [#10013](https://github.com/pydantic/pydantic/pull/10013) * Simplify internal generics logic - remove generator overhead by @sydney-runkle in [#10059](https://github.com/pydantic/pydantic/pull/10059) * Remove default module globals from types namespace by @sydney-runkle in [#10123](https://github.com/pydantic/pydantic/pull/10123) * Performance boost: skip caching parent namespaces in most cases by @sydney-runkle in [#10113](https://github.com/pydantic/pydantic/pull/10113) * Update ns stack with already copied ns by @sydney-runkle in [#10267](https://github.com/pydantic/pydantic/pull/10267) ##### Minor Internal Improvements * ⚡️ Speed up `multiple_of_validator()` by 31% in `pydantic/_internal/_validators.py` by @misrasaurabh1 in [#9839](https://github.com/pydantic/pydantic/pull/9839) * ⚡️ Speed up `ModelPrivateAttr.__set_name__()` by 18% in `pydantic/fields.py` by @misrasaurabh1 in [#9841](https://github.com/pydantic/pydantic/pull/9841) * ⚡️ Speed up `dataclass()` by 7% in `pydantic/dataclasses.py` by @misrasaurabh1 in [#9843](https://github.com/pydantic/pydantic/pull/9843) * ⚡️ Speed up function `_field_name_for_signature` by 37% in `pydantic/_internal/_signature.py` by @misrasaurabh1 in [#9951](https://github.com/pydantic/pydantic/pull/9951) * ⚡️ Speed up method `GenerateSchema._unpack_refs_defs` by 26% in `pydantic/_internal/_generate_schema.py` by @misrasaurabh1 in [#9949](https://github.com/pydantic/pydantic/pull/9949) * ⚡️ Speed up function `apply_each_item_validators` by 100% in `pydantic/_internal/_generate_schema.py` by @misrasaurabh1 in [#9950](https://github.com/pydantic/pydantic/pull/9950) * ⚡️ Speed up method `ConfigWrapper.core_config` by 28% in `pydantic/_internal/_config.py` by @misrasaurabh1 in [#9953](https://github.com/pydantic/pydantic/pull/9953) #### Fixes * Respect `use_enum_values` on `Literal` types by @kwint in [#9787](https://github.com/pydantic/pydantic/pull/9787) * Prevent type error for exotic `BaseModel/RootModel` inheritance by @dmontagu in [#9913](https://github.com/pydantic/pydantic/pull/9913) * Fix typing issue with field_validator-decorated methods by @dmontagu in [#9914](https://github.com/pydantic/pydantic/pull/9914) * Replace `str` type annotation with `Any` in validator factories in documentation on validators by @maximilianfellhuber in [#9885](https://github.com/pydantic/pydantic/pull/9885) * Fix `ComputedFieldInfo.wrapped_property` pointer when a property setter is assigned by @tlambert03 in [#9892](https://github.com/pydantic/pydantic/pull/9892) * Fix recursive typing of `main.IncEnx` by @tlambert03 in [#9924](https://github.com/pydantic/pydantic/pull/9924) * Allow usage of `type[Annotated[...]]` by @Viicos in [#9932](https://github.com/pydantic/pydantic/pull/9932) * `mypy` plugin: handle frozen fields on a per-field basis by @dmontagu in [#9935](https://github.com/pydantic/pydantic/pull/9935) * Fix typo in `invalid-annotated-type` error code by @sydney-runkle in [#9948](https://github.com/pydantic/pydantic/pull/9948) * Simplify schema generation for `uuid`, `url`, and `ip` types by @sydney-runkle in [#9975](https://github.com/pydantic/pydantic/pull/9975) * Move `date` schemas to `_generate_schema.py` by @sydney-runkle in [#9976](https://github.com/pydantic/pydantic/pull/9976) * Move `decimal.Decimal` validation to `_generate_schema.py` by @sydney-runkle in [#9977](https://github.com/pydantic/pydantic/pull/9977) * Simplify IP address schema in `_std_types_schema.py` by @sydney-runkle in [#9959](https://github.com/pydantic/pydantic/pull/9959) * Fix type annotations for some potentially generic `GenerateSchema.match_type` options by @sydney-runkle in [#9961](https://github.com/pydantic/pydantic/pull/9961) * Add class name to "has conflict" warnings by @msabramo in [#9964](https://github.com/pydantic/pydantic/pull/9964) * Fix `dataclass` ignoring `default_factory` passed in Annotated by @kc0506 in [#9971](https://github.com/pydantic/pydantic/pull/9971) * Fix `Sequence` ignoring `discriminator` by @kc0506 in [#9980](https://github.com/pydantic/pydantic/pull/9980) * Fix typing for `IPvAnyAddress` and `IPvAnyInterface` by @haoyun in [#9990](https://github.com/pydantic/pydantic/pull/9990) * Fix false positives on v1 models in `mypy` plugin for `from_orm` check requiring from_attributes=True config by @radekwlsk in [#9938](https://github.com/pydantic/pydantic/pull/9938) * Apply `strict=True` to `__init__` in `mypy` plugin by @kc0506 in [#9998](https://github.com/pydantic/pydantic/pull/9998) * Refactor application of `deque` annotations by @sydney-runkle in [#10018](https://github.com/pydantic/pydantic/pull/10018) * Raise a better user error when failing to evaluate a forward reference by @Viicos in [#10030](https://github.com/pydantic/pydantic/pull/10030) * Fix evaluation of `__pydantic_extra__` annotation in specific circumstances by @Viicos in [#10070](https://github.com/pydantic/pydantic/pull/10070) * Fix `frozen` enforcement for `dataclasses` by @sydney-runkle in [#10066](https://github.com/pydantic/pydantic/pull/10066) * Remove logic to handle unused `__get_pydantic_core_schema__` signature by @Viicos in [#10075](https://github.com/pydantic/pydantic/pull/10075) * Use `is_annotated` consistently by @Viicos in [#10095](https://github.com/pydantic/pydantic/pull/10095) * Fix `PydanticDeprecatedSince26` typo by @kc0506 in [#10101](https://github.com/pydantic/pydantic/pull/10101) * Improve `pyright` tests, refactor model decorators signatures by @Viicos in [#10092](https://github.com/pydantic/pydantic/pull/10092) * Fix `ip` serialization logic by @sydney-runkle in [#10112](https://github.com/pydantic/pydantic/pull/10112) * Warn when frozen defined twice for `dataclasses` by @mochi22 in [#10082](https://github.com/pydantic/pydantic/pull/10082) * Do not compute JSON Schema default when plain serializers are used with `when_used` set to `'json-unless-none'` and the default value is `None` by @Viicos in [#10121](https://github.com/pydantic/pydantic/pull/10121) * Fix `ImportString` special cases by @sydney-runkle in [#10137](https://github.com/pydantic/pydantic/pull/10137) * Blacklist default globals to support exotic user code with `__` prefixed annotations by @sydney-runkle in [#10136](https://github.com/pydantic/pydantic/pull/10136) * Handle `nullable` schemas with `serialization` schema available during JSON Schema generation by @Viicos in [#10132](https://github.com/pydantic/pydantic/pull/10132) * Reorganize `BaseModel` annotations by @kc0506 in [#10110](https://github.com/pydantic/pydantic/pull/10110) * Fix core schema simplification when serialization schemas are involved in specific scenarios by @Viicos in [#10155](https://github.com/pydantic/pydantic/pull/10155) * Add support for stringified annotations when using `PrivateAttr` with `Annotated` by @Viicos in [#10157](https://github.com/pydantic/pydantic/pull/10157) * Fix JSON Schema `number` type for literal and enum schemas by @Viicos in [#10172](https://github.com/pydantic/pydantic/pull/10172) * Fix JSON Schema generation of fields with plain validators in serialization mode by @Viicos in [#10167](https://github.com/pydantic/pydantic/pull/10167) * Fix invalid JSON Schemas being generated for functions in certain scenarios by @Viicos in [#10188](https://github.com/pydantic/pydantic/pull/10188) * Make sure generated JSON Schemas are valid in tests by @Viicos in [#10182](https://github.com/pydantic/pydantic/pull/10182) * Fix key error with custom serializer by @sydney-runkle in [#10200](https://github.com/pydantic/pydantic/pull/10200) * Add 'wss' for allowed schemes in NatsDsn by @swelborn in [#10224](https://github.com/pydantic/pydantic/pull/10224) * Fix `Mapping` and `MutableMapping` annotations to use mapping schema instead of dict schema by @sydney-runkle in [#10020](https://github.com/pydantic/pydantic/pull/10020) * Fix JSON Schema generation for constrained dates by @Viicos in [#10185](https://github.com/pydantic/pydantic/pull/10185) * Fix discriminated union bug regression when using enums by @kfreezen in [pydantic/pydantic-core#1286](https://github.com/pydantic/pydantic-core/pull/1286) * Fix `field_serializer` with computed field when using `*` by @nix010 in [pydantic/pydantic-core#1349](https://github.com/pydantic/pydantic-core/pull/1349) * Try each option in `Union` serializer before inference by @sydney-runkle in [pydantic/pydantic-core#1398](https://github.com/pydantic/pydantic-core/pull/1398) * Fix `float` serialization behavior in `strict` mode by @sydney-runkle in [pydantic/pydantic-core#1400](https://github.com/pydantic/pydantic-core/pull/1400) * Introduce `exactness` into Decimal validation logic to improve union validation behavior by @sydney-runkle in in [pydantic/pydantic-core#1405](https://github.com/pydantic/pydantic-core/pull/1405) * Fix new warnings assertions to use `pytest.warns()` by @mgorny in [#10241](https://github.com/pydantic/pydantic/pull/10241) * Fix a crash when cleaning the namespace in `ModelMetaclass` by @Viicos in [#10242](https://github.com/pydantic/pydantic/pull/10242) * Fix parent namespace issue with model rebuilds by @sydney-runkle in [#10257](https://github.com/pydantic/pydantic/pull/10257) * Remove defaults filter for namespace by @sydney-runkle in [#10261](https://github.com/pydantic/pydantic/pull/10261) * Use identity instead of equality after validating model in `__init__` by @Viicos in [#10264](https://github.com/pydantic/pydantic/pull/10264) * Support `BigInt` serialization for `int` subclasses by @kxx317 in [pydantic/pydantic-core#1417](https://github.com/pydantic/pydantic-core/pull/1417) * Support signature for wrap validators without `info` by @sydney-runkle in [#10277](https://github.com/pydantic/pydantic/pull/10277) * Ensure `__pydantic_complete__` is set when rebuilding `dataclasses` by @Viicos in [#10291](https://github.com/pydantic/pydantic/pull/10291) * Respect `schema_generator` config value in `TypeAdapter` by @sydney-runkle in [#10300](https://github.com/pydantic/pydantic/pull/10300) #### Packaging * Bump `ruff` to `v0.5.0` and `pyright` to `v1.1.369` by @sydney-runkle in [#9801](https://github.com/pydantic/pydantic/pull/9801) * Bump `pydantic-extra-types` to `v2.9.0` by @sydney-runkle in [#9832](https://github.com/pydantic/pydantic/pull/9832) * Support compatibility with `pdm v2.18.1` by @Viicos in [#10138](https://github.com/pydantic/pydantic/pull/10138) * Bump `v1` version stub to `v1.10.18` by @sydney-runkle in [#10214](https://github.com/pydantic/pydantic/pull/10214) * Bump `pydantic-core` to `v2.23.2` by @sydney-runkle in [#10311](https://github.com/pydantic/pydantic/pull/10311) ### New Contributors #### `pydantic` * @kwint made their first contribution in [#9787](https://github.com/pydantic/pydantic/pull/9787) * @seekinginfiniteloop made their first contribution in [#9822](https://github.com/pydantic/pydantic/pull/9822) * @a-alexander made their first contribution in [#9848](https://github.com/pydantic/pydantic/pull/9848) * @maximilianfellhuber made their first contribution in [#9885](https://github.com/pydantic/pydantic/pull/9885) * @karmaBonfire made their first contribution in [#9945](https://github.com/pydantic/pydantic/pull/9945) * @s-rigaud made their first contribution in [#9958](https://github.com/pydantic/pydantic/pull/9958) * @msabramo made their first contribution in [#9964](https://github.com/pydantic/pydantic/pull/9964) * @DimaCybr made their first contribution in [#9972](https://github.com/pydantic/pydantic/pull/9972) * @kc0506 made their first contribution in [#9971](https://github.com/pydantic/pydantic/pull/9971) * @haoyun made their first contribution in [#9990](https://github.com/pydantic/pydantic/pull/9990) * @radekwlsk made their first contribution in [#9938](https://github.com/pydantic/pydantic/pull/9938) * @dpeachey made their first contribution in [#10029](https://github.com/pydantic/pydantic/pull/10029) * @BoxyUwU made their first contribution in [#10085](https://github.com/pydantic/pydantic/pull/10085) * @mochi22 made their first contribution in [#10082](https://github.com/pydantic/pydantic/pull/10082) * @aditkumar72 made their first contribution in [#10128](https://github.com/pydantic/pydantic/pull/10128) * @changhc made their first contribution in [#9654](https://github.com/pydantic/pydantic/pull/9654) * @insumanth made their first contribution in [#10229](https://github.com/pydantic/pydantic/pull/10229) * @AdolfoVillalobos made their first contribution in [#10240](https://github.com/pydantic/pydantic/pull/10240) * @bllchmbrs made their first contribution in [#10270](https://github.com/pydantic/pydantic/pull/10270) #### `pydantic-core` * @kfreezen made their first contribution in [pydantic/pydantic-core#1286](https://github.com/pydantic/pydantic-core/pull/1286) * @tinez made their first contribution in [pydantic/pydantic-core#1368](https://github.com/pydantic/pydantic-core/pull/1368) * @fft001 made their first contribution in [pydantic/pydantic-core#1362](https://github.com/pydantic/pydantic-core/pull/1362) * @nix010 made their first contribution in [pydantic/pydantic-core#1349](https://github.com/pydantic/pydantic-core/pull/1349) * @BoxyUwU made their first contribution in [pydantic/pydantic-core#1379](https://github.com/pydantic/pydantic-core/pull/1379) * @candleindark made their first contribution in [pydantic/pydantic-core#1404](https://github.com/pydantic/pydantic-core/pull/1404) * @changhc made their first contribution in [pydantic/pydantic-core#1331](https://github.com/pydantic/pydantic-core/pull/1331) ## v2.9.0b2 (2024-08-30) Pre-release, see [the GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.9.0b2) for details. ## v2.9.0b1 (2024-08-26) Pre-release, see [the GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.9.0b1) for details. ## v2.8.2 (2024-07-03) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.8.2) ### What's Changed #### Fixes * Fix issue with assertion caused by pluggable schema validator by @dmontagu in [#9838](https://github.com/pydantic/pydantic/pull/9838) ## v2.8.1 (2024-07-03) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.8.1) ### What's Changed #### Packaging * Bump `ruff` to `v0.5.0` and `pyright` to `v1.1.369` by @sydney-runkle in [#9801](https://github.com/pydantic/pydantic/pull/9801) * Bump `pydantic-core` to `v2.20.1`, `pydantic-extra-types` to `v2.9.0` by @sydney-runkle in [#9832](https://github.com/pydantic/pydantic/pull/9832) #### Fixes * Fix breaking change in `to_snake` from v2.7 -> v2.8 by @sydney-runkle in [#9812](https://github.com/pydantic/pydantic/pull/9812) * Fix list constraint json schema application by @sydney-runkle in [#9818](https://github.com/pydantic/pydantic/pull/9818) * Support time duration more than 23 by @nix010 in [pydantic/speedate#64](https://github.com/pydantic/speedate/pull/64) * Fix millisecond fraction being handled with the wrong scale by @davidhewitt in [pydantic/speedate#65](https://github.com/pydantic/speedate/pull/65) * Handle negative fractional durations correctly by @sydney-runkle in [pydantic/speedate#71](https://github.com/pydantic/speedate/pull/71) ## v2.8.0 (2024-07-01) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.8.0) The code released in v2.8.0 is functionally identical to that of v2.8.0b1. ### What's Changed #### Packaging * Update citation version automatically with new releases by @sydney-runkle in [#9673](https://github.com/pydantic/pydantic/pull/9673) * Bump pyright to `v1.1.367` and add type checking tests for pipeline API by @adriangb in [#9674](https://github.com/pydantic/pydantic/pull/9674) * Update `pydantic.v1` stub to `v1.10.17` by @sydney-runkle in [#9707](https://github.com/pydantic/pydantic/pull/9707) * General package updates to prep for `v2.8.0b1` by @sydney-runkle in [#9741](https://github.com/pydantic/pydantic/pull/9741) * Bump `pydantic-core` to `v2.20.0` by @sydney-runkle in [#9745](https://github.com/pydantic/pydantic/pull/9745) * Add support for Python 3.13 by @sydney-runkle in [#9743](https://github.com/pydantic/pydantic/pull/9743) * Update `pdm` version used for `pdm.lock` to v2.16.1 by @sydney-runkle in [#9761](https://github.com/pydantic/pydantic/pull/9761) * Update to `ruff` `v0.4.8` by @Viicos in [#9585](https://github.com/pydantic/pydantic/pull/9585) #### New Features * Experimental: support `defer_build` for `TypeAdapter` by @MarkusSintonen in [#8939](https://github.com/pydantic/pydantic/pull/8939) * Implement `deprecated` field in json schema by @NeevCohen in [#9298](https://github.com/pydantic/pydantic/pull/9298) * Experimental: Add pipeline API by @adriangb in [#9459](https://github.com/pydantic/pydantic/pull/9459) * Add support for programmatic title generation by @NeevCohen in [#9183](https://github.com/pydantic/pydantic/pull/9183) * Implement `fail_fast` feature by @uriyyo in [#9708](https://github.com/pydantic/pydantic/pull/9708) * Add `ser_json_inf_nan='strings'` mode to produce valid JSON by @josh-newman in [pydantic/pydantic-core#1307](https://github.com/pydantic/pydantic-core/pull/1307) #### Changes * Add warning when "alias" is set in ignored `Annotated` field by @nix010 in [#9170](https://github.com/pydantic/pydantic/pull/9170) * Support serialization of some serializable defaults in JSON schema by @sydney-runkle in [#9624](https://github.com/pydantic/pydantic/pull/9624) * Relax type specification for `__validators__` values in `create_model` by @sydney-runkle in [#9697](https://github.com/pydantic/pydantic/pull/9697) * **Breaking Change:** Improve `smart` union matching logic by @sydney-runkle in [pydantic/pydantic-core#1322](https://github.com/pydantic/pydantic-core/pull/1322) You can read more about our `smart` union matching logic [here](https://docs.pydantic.dev/dev/concepts/unions/#smart-mode). In some cases, if the old behavior is desired, you can switch to `left-to-right` mode and change the order of your `Union` members. #### Performance ##### Internal Improvements * ⚡️ Speed up `_display_error_loc()` by 25% in `pydantic/v1/error_wrappers.py` by @misrasaurabh1 in [#9653](https://github.com/pydantic/pydantic/pull/9653) * ⚡️ Speed up `_get_all_json_refs()` by 34% in `pydantic/json_schema.py` by @misrasaurabh1 in [#9650](https://github.com/pydantic/pydantic/pull/9650) * ⚡️ Speed up `is_pydantic_dataclass()` by 41% in `pydantic/dataclasses.py` by @misrasaurabh1 in [#9652](https://github.com/pydantic/pydantic/pull/9652) * ⚡️ Speed up `to_snake()` by 27% in `pydantic/alias_generators.py` by @misrasaurabh1 in [#9747](https://github.com/pydantic/pydantic/pull/9747) * ⚡️ Speed up `unwrap_wrapped_function()` by 93% in `pydantic/_internal/_decorators.py` by @misrasaurabh1 in [#9727](https://github.com/pydantic/pydantic/pull/9727) #### Fixes * Replace `__spec__.parent` with `__package__` by @hramezani in [#9331](https://github.com/pydantic/pydantic/pull/9331) * Fix Outputted Model JSON Schema for `Sequence` type by @anesmemisevic in [#9303](https://github.com/pydantic/pydantic/pull/9303) * Fix typing of `_frame_depth` by @Viicos in [#9353](https://github.com/pydantic/pydantic/pull/9353) * Make `ImportString` json schema compatible by @amitschang in [#9344](https://github.com/pydantic/pydantic/pull/9344) * Hide private attributes (`PrivateAttr`) from `__init__` signature in type checkers by @idan22moral in [#9293](https://github.com/pydantic/pydantic/pull/9293) * Make detection of `TypeVar` defaults robust to the CPython `PEP-696` implementation by @AlexWaygood in [#9426](https://github.com/pydantic/pydantic/pull/9426) * Fix usage of `PlainSerializer` with builtin types by @Viicos in [#9450](https://github.com/pydantic/pydantic/pull/9450) * Add more robust custom validation examples by @ChrisPappalardo in [#9468](https://github.com/pydantic/pydantic/pull/9468) * Fix ignored `strict` specification for `StringConstraint(strict=False)` by @vbmendes in [#9476](https://github.com/pydantic/pydantic/pull/9476) * **Breaking Change:** Use PEP 570 syntax by @Viicos in [#9479](https://github.com/pydantic/pydantic/pull/9479) * Use `Self` where possible by @Viicos in [#9479](https://github.com/pydantic/pydantic/pull/9479) * Do not alter `RootModel.model_construct` signature in the `mypy` plugin by @Viicos in [#9480](https://github.com/pydantic/pydantic/pull/9480) * Fixed type hint of `validation_context` by @OhioDschungel6 in [#9508](https://github.com/pydantic/pydantic/pull/9508) * Support context being passed to TypeAdapter's `dump_json`/`dump_python` by @alexcouper in [#9495](https://github.com/pydantic/pydantic/pull/9495) * Updates type signature for `Field()` constructor by @bjmc in [#9484](https://github.com/pydantic/pydantic/pull/9484) * Improve builtin alias generators by @sydney-runkle in [#9561](https://github.com/pydantic/pydantic/pull/9561) * Fix typing of `TypeAdapter` by @Viicos in [#9570](https://github.com/pydantic/pydantic/pull/9570) * Add fallback default value for private fields in `__setstate__` of BaseModel by @anhpham1509 in [#9584](https://github.com/pydantic/pydantic/pull/9584) * Support `PEP 746` by @adriangb in [#9587](https://github.com/pydantic/pydantic/pull/9587) * Allow validator and serializer functions to have default values by @Viicos in [#9478](https://github.com/pydantic/pydantic/pull/9478) * Fix bug with mypy plugin's handling of covariant `TypeVar` fields by @dmontagu in [#9606](https://github.com/pydantic/pydantic/pull/9606) * Fix multiple annotation / constraint application logic by @sydney-runkle in [#9623](https://github.com/pydantic/pydantic/pull/9623) * Respect `regex` flags in validation and json schema by @sydney-runkle in [#9591](https://github.com/pydantic/pydantic/pull/9591) * Fix type hint on `IpvAnyAddress` by @sydney-runkle in [#9640](https://github.com/pydantic/pydantic/pull/9640) * Allow a field specifier on `__pydantic_extra__` by @dmontagu in [#9659](https://github.com/pydantic/pydantic/pull/9659) * Use normalized case for file path comparison by @sydney-runkle in [#9737](https://github.com/pydantic/pydantic/pull/9737) * Modify constraint application logic to allow field constraints on `Optional[Decimal]` by @lazyhope in [#9754](https://github.com/pydantic/pydantic/pull/9754) * `validate_call` type params fix by @sydney-runkle in [#9760](https://github.com/pydantic/pydantic/pull/9760) * Check all warnings returned by pytest.warns() by @s-t-e-v-e-n-k in [#9702](https://github.com/pydantic/pydantic/pull/9702) * Reuse `re.Pattern` object in regex patterns to allow for regex flags by @sydney-runkle in [pydantic/pydantic-core#1318](https://github.com/pydantic/pydantic-core/pull/1318) ### New Contributors * @idan22moral made their first contribution in [#9294](https://github.com/pydantic/pydantic/pull/9294) * @anesmemisevic made their first contribution in [#9303](https://github.com/pydantic/pydantic/pull/9303) * @max-muoto made their first contribution in [#9338](https://github.com/pydantic/pydantic/pull/9338) * @amitschang made their first contribution in [#9344](https://github.com/pydantic/pydantic/pull/9344) * @paulmartin91 made their first contribution in [#9410](https://github.com/pydantic/pydantic/pull/9410) * @OhioDschungel6 made their first contribution in [#9405](https://github.com/pydantic/pydantic/pull/9405) * @AlexWaygood made their first contribution in [#9426](https://github.com/pydantic/pydantic/pull/9426) * @kinuax made their first contribution in [#9433](https://github.com/pydantic/pydantic/pull/9433) * @antoni-jamiolkowski made their first contribution in [#9431](https://github.com/pydantic/pydantic/pull/9431) * @candleindark made their first contribution in [#9448](https://github.com/pydantic/pydantic/pull/9448) * @nix010 made their first contribution in [#9170](https://github.com/pydantic/pydantic/pull/9170) * @tomy0000000 made their first contribution in [#9457](https://github.com/pydantic/pydantic/pull/9457) * @vbmendes made their first contribution in [#9470](https://github.com/pydantic/pydantic/pull/9470) * @micheleAlberto made their first contribution in [#9471](https://github.com/pydantic/pydantic/pull/9471) * @ChrisPappalardo made their first contribution in [#9468](https://github.com/pydantic/pydantic/pull/9468) * @blueTurtz made their first contribution in [#9475](https://github.com/pydantic/pydantic/pull/9475) * @WinterBlue16 made their first contribution in [#9477](https://github.com/pydantic/pydantic/pull/9477) * @bittner made their first contribution in [#9500](https://github.com/pydantic/pydantic/pull/9500) * @alexcouper made their first contribution in [#9495](https://github.com/pydantic/pydantic/pull/9495) * @bjmc made their first contribution in [#9484](https://github.com/pydantic/pydantic/pull/9484) * @pjvv made their first contribution in [#9529](https://github.com/pydantic/pydantic/pull/9529) * @nedbat made their first contribution in [#9530](https://github.com/pydantic/pydantic/pull/9530) * @gunnellEvan made their first contribution in [#9469](https://github.com/pydantic/pydantic/pull/9469) * @jaymbans made their first contribution in [#9531](https://github.com/pydantic/pydantic/pull/9531) * @MarcBresson made their first contribution in [#9534](https://github.com/pydantic/pydantic/pull/9534) * @anhpham1509 made their first contribution in [#9584](https://github.com/pydantic/pydantic/pull/9584) * @K-dash made their first contribution in [#9595](https://github.com/pydantic/pydantic/pull/9595) * @s-t-e-v-e-n-k made their first contribution in [#9527](https://github.com/pydantic/pydantic/pull/9527) * @airwoodix made their first contribution in [#9506](https://github.com/pydantic/pydantic/pull/9506) * @misrasaurabh1 made their first contribution in [#9653](https://github.com/pydantic/pydantic/pull/9653) * @AlessandroMiola made their first contribution in [#9740](https://github.com/pydantic/pydantic/pull/9740) * @mylapallilavanyaa made their first contribution in [#9746](https://github.com/pydantic/pydantic/pull/9746) * @lazyhope made their first contribution in [#9754](https://github.com/pydantic/pydantic/pull/9754) * @YassinNouh21 made their first contribution in [#9759](https://github.com/pydantic/pydantic/pull/9759) ## v2.8.0b1 (2024-06-27) Pre-release, see [the GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.8.0b1) for details. ## v2.7.4 (2024-06-12) [Github release](https://github.com/pydantic/pydantic/releases/tag/v2.7.4) ### What's Changed #### Packaging * Bump `pydantic.v1` to `v1.10.16` reference by @sydney-runkle in [#9639](https://github.com/pydantic/pydantic/pull/9639) #### Fixes * Specify `recursive_guard` as kwarg in `FutureRef._evaluate` by @vfazio in [#9612](https://github.com/pydantic/pydantic/pull/9612) ## v2.7.3 (2024-06-03) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.7.3) ### What's Changed #### Packaging * Bump `pydantic-core` to `v2.18.4` by @sydney-runkle in [#9550](https://github.com/pydantic/pydantic/pull/9550) #### Fixes * Fix u style unicode strings in python @samuelcolvin in [pydantic/jiter#110](https://github.com/pydantic/jiter/pull/110) ## v2.7.2 (2024-05-28) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.7.2) ### What's Changed #### Packaging * Bump `pydantic-core` to `v2.18.3` by @sydney-runkle in [#9515](https://github.com/pydantic/pydantic/pull/9515) #### Fixes * Replace `__spec__.parent` with `__package__` by @hramezani in [#9331](https://github.com/pydantic/pydantic/pull/9331) * Fix validation of `int`s with leading unary minus by @RajatRajdeep in [pydantic/pydantic-core#1291](https://github.com/pydantic/pydantic-core/pull/1291) * Fix `str` subclass validation for enums by @sydney-runkle in [pydantic/pydantic-core#1273](https://github.com/pydantic/pydantic-core/pull/1273) * Support `BigInt`s in `Literal`s and `Enum`s by @samuelcolvin in [pydantic/pydantic-core#1297](https://github.com/pydantic/pydantic-core/pull/1297) * Fix: uuid - allow `str` subclass as input by @davidhewitt in [pydantic/pydantic-core#1296](https://github.com/pydantic/pydantic-core/pull/1296) ## v2.7.1 (2024-04-23) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.7.1) ### What's Changed #### Packaging * Bump `pydantic-core` to `v2.18.2` by @sydney-runkle in [#9307](https://github.com/pydantic/pydantic/pull/9307) #### New Features * Ftp and Websocket connection strings support by @CherrySuryp in [#9205](https://github.com/pydantic/pydantic/pull/9205) #### Changes * Use field description for RootModel schema description when there is `…` by @LouisGobert in [#9214](https://github.com/pydantic/pydantic/pull/9214) #### Fixes * Fix `validation_alias` behavior with `model_construct` for `AliasChoices` and `AliasPath` by @sydney-runkle in [#9223](https://github.com/pydantic/pydantic/pull/9223) * Revert `typing.Literal` and import it outside the TYPE_CHECKING block by @frost-nzcr4 in [#9232](https://github.com/pydantic/pydantic/pull/9232) * Fix `Secret` serialization schema, applicable for unions by @sydney-runkle in [#9240](https://github.com/pydantic/pydantic/pull/9240) * Fix `strict` application to `function-after` with `use_enum_values` by @sydney-runkle in [#9279](https://github.com/pydantic/pydantic/pull/9279) * Address case where `model_construct` on a class which defines `model_post_init` fails with `AttributeError` by @babygrimes in [#9168](https://github.com/pydantic/pydantic/pull/9168) * Fix `model_json_schema` with config types by @NeevCohen in [#9287](https://github.com/pydantic/pydantic/pull/9287) * Support multiple zeros as an `int` by @samuelcolvin in [pydantic/pydantic-core#1269](https://github.com/pydantic/pydantic-core/pull/1269) * Fix validation of `int`s with leading unary plus by @cknv in [pydantic/pydantic-core#1272](https://github.com/pydantic/pydantic-core/pull/1272) * Fix interaction between `extra != 'ignore'` and `from_attributes=True` by @davidhewitt in [pydantic/pydantic-core#1276](https://github.com/pydantic/pydantic-core/pull/1276) * Handle error from `Enum`'s `missing` function as `ValidationError` by @sydney-runkle in [pydantic/pydantic-core#1274](https://github.com/pydantic/pydantic-core/pull/1754) * Fix memory leak with `Iterable` validation by @davidhewitt in [pydantic/pydantic-core#1271](https://github.com/pydantic/pydantic-core/pull/1751) ### New Contributors * @zzstoatzz made their first contribution in [#9219](https://github.com/pydantic/pydantic/pull/9219) * @frost-nzcr4 made their first contribution in [#9232](https://github.com/pydantic/pydantic/pull/9232) * @CherrySuryp made their first contribution in [#9205](https://github.com/pydantic/pydantic/pull/9205) * @vagenas made their first contribution in [#9268](https://github.com/pydantic/pydantic/pull/9268) * @ollz272 made their first contribution in [#9262](https://github.com/pydantic/pydantic/pull/9262) * @babygrimes made their first contribution in [#9168](https://github.com/pydantic/pydantic/pull/9168) * @swelborn made their first contribution in [#9296](https://github.com/pydantic/pydantic/pull/9296) * @kf-novi made their first contribution in [#9236](https://github.com/pydantic/pydantic/pull/9236) * @lgeiger made their first contribution in [#9288](https://github.com/pydantic/pydantic/pull/9288) ## v2.7.0 (2024-04-11) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.7.0) The code released in v2.7.0 is practically identical to that of v2.7.0b1. ### What's Changed #### Packaging * Reorganize `pyproject.toml` sections by @Viicos in [#8899](https://github.com/pydantic/pydantic/pull/8899) * Bump `pydantic-core` to `v2.18.1` by @sydney-runkle in [#9211](https://github.com/pydantic/pydantic/pull/9211) * Adopt `jiter` `v0.2.0` by @samuelcolvin in [pydantic/pydantic-core#1250](https://github.com/pydantic/pydantic-core/pull/1250) #### New Features * Extract attribute docstrings from `FieldInfo.description` by @Viicos in [#6563](https://github.com/pydantic/pydantic/pull/6563) * Add a `with_config` decorator to comply with typing spec by @Viicos in [#8611](https://github.com/pydantic/pydantic/pull/8611) * Allow an optional separator splitting the value and unit of the result of `ByteSize.human_readable` by @jks15satoshi in [#8706](https://github.com/pydantic/pydantic/pull/8706) * Add generic `Secret` base type by @conradogarciaberrotaran in [#8519](https://github.com/pydantic/pydantic/pull/8519) * Make use of `Sphinx` inventories for cross references in docs by @Viicos in [#8682](https://github.com/pydantic/pydantic/pull/8682) * Add environment variable to disable plugins by @geospackle in [#8767](https://github.com/pydantic/pydantic/pull/8767) * Add support for `deprecated` fields by @Viicos in [#8237](https://github.com/pydantic/pydantic/pull/8237) * Allow `field_serializer('*')` by @ornariece in [#9001](https://github.com/pydantic/pydantic/pull/9001) * Handle a case when `model_config` is defined as a model property by @alexeyt101 in [#9004](https://github.com/pydantic/pydantic/pull/9004) * Update `create_model()` to support `typing.Annotated` as input by @wannieman98 in [#8947](https://github.com/pydantic/pydantic/pull/8947) * Add `ClickhouseDsn` support by @solidguy7 in [#9062](https://github.com/pydantic/pydantic/pull/9062) * Add support for `re.Pattern[str]` to `pattern` field by @jag-k in [#9053](https://github.com/pydantic/pydantic/pull/9053) * Support for `serialize_as_any` runtime setting by @sydney-runkle in [#8830](https://github.com/pydantic/pydantic/pull/8830) * Add support for `typing.Self` by @Youssefares in [#9023](https://github.com/pydantic/pydantic/pull/9023) * Ability to pass `context` to serialization by @ornariece in [#8965](https://github.com/pydantic/pydantic/pull/8965) * Add feedback widget to docs with flarelytics integration by @sydney-runkle in [#9129](https://github.com/pydantic/pydantic/pull/9129) * Support for parsing partial JSON strings in Python by @samuelcolvin in [pydantic/jiter#66](https://github.com/pydantic/jiter/pull/66) **Finalized in v2.7.0, rather than v2.7.0b1:** * Add support for field level number to str coercion option by @NeevCohen in [#9137](https://github.com/pydantic/pydantic/pull/9137) * Update `warnings` parameter for serialization utilities to allow raising a warning by @Lance-Drane in [#9166](https://github.com/pydantic/pydantic/pull/9166) #### Changes * Correct docs, logic for `model_construct` behavior with `extra` by @sydney-runkle in [#8807](https://github.com/pydantic/pydantic/pull/8807) * Improve error message for improper `RootModel` subclasses by @sydney-runkle in [#8857](https://github.com/pydantic/pydantic/pull/8857) * **Breaking Change:** Use `PEP570` syntax by @Viicos in [#8940](https://github.com/pydantic/pydantic/pull/8940) * Add `enum` and `type` to the JSON schema for single item literals by @dmontagu in [#8944](https://github.com/pydantic/pydantic/pull/8944) * Deprecate `update_json_schema` internal function by @sydney-runkle in [#9125](https://github.com/pydantic/pydantic/pull/9125) * Serialize duration to hour minute second, instead of just seconds by @kakilangit in [pydantic/speedate#50](https://github.com/pydantic/speedate/pull/50) * Trimming str before parsing to int and float by @hungtsetse in [pydantic/pydantic-core#1203](https://github.com/pydantic/pydantic-core/pull/1203) #### Performance * `enum` validator improvements by @samuelcolvin in [#9045](https://github.com/pydantic/pydantic/pull/9045) * Move `enum` validation and serialization to Rust by @samuelcolvin in [#9064](https://github.com/pydantic/pydantic/pull/9064) * Improve schema generation for nested dataclasses by @sydney-runkle in [#9114](https://github.com/pydantic/pydantic/pull/9114) * Fast path for ASCII python string creation in JSON by @samuelcolvin in in [pydantic/jiter#72](https://github.com/pydantic/jiter/pull/72) * SIMD integer and string JSON parsing on `aarch64`(**Note:** SIMD on x86 will be implemented in a future release) by @samuelcolvin in in [pydantic/jiter#65](https://github.com/pydantic/jiter/pull/65) * Support JSON `Cow` from `jiter` by @davidhewitt in [pydantic/pydantic-core#1231](https://github.com/pydantic/pydantic-core/pull/1231) * MAJOR performance improvement: update to PyO3 0.21 final by @davidhewitt in [pydantic/pydantic-core#1248](https://github.com/pydantic/pydantic-core/pull/1248) * cache Python strings by @samuelcolvin in [pydantic/pydantic-core#1240](https://github.com/pydantic/pydantic-core/pull/1240) #### Fixes * Fix strict parsing for some `Sequence`s by @sydney-runkle in [#8614](https://github.com/pydantic/pydantic/pull/8614) * Add a check on the existence of `__qualname__` by @anci3ntr0ck in [#8642](https://github.com/pydantic/pydantic/pull/8642) * Handle `__pydantic_extra__` annotation being a string or inherited by @alexmojaki in [#8659](https://github.com/pydantic/pydantic/pull/8659) * Fix json validation for `NameEmail` by @Holi0317 in [#8650](https://github.com/pydantic/pydantic/pull/8650) * Fix type-safety of attribute access in `BaseModel` by @bluenote10 in [#8651](https://github.com/pydantic/pydantic/pull/8651) * Fix bug with `mypy` plugin and `no_strict_optional = True` by @dmontagu in [#8666](https://github.com/pydantic/pydantic/pull/8666) * Fix `ByteSize` error `type` change by @sydney-runkle in [#8681](https://github.com/pydantic/pydantic/pull/8681) * Fix inheriting annotations in dataclasses by @sydney-runkle in [#8679](https://github.com/pydantic/pydantic/pull/8679) * Fix regression in core schema generation for indirect definition references by @dmontagu in [#8702](https://github.com/pydantic/pydantic/pull/8702) * Fix unsupported types bug with plain validator by @sydney-runkle in [#8710](https://github.com/pydantic/pydantic/pull/8710) * Reverting problematic fix from 2.6 release, fixing schema building bug by @sydney-runkle in [#8718](https://github.com/pydantic/pydantic/pull/8718) * fixes `__pydantic_config__` ignored for TypeDict by @13sin in [#8734](https://github.com/pydantic/pydantic/pull/8734) * Fix test failures with `pytest v8.0.0` due to `pytest.warns()` starting to work inside `pytest.raises()` by @mgorny in [#8678](https://github.com/pydantic/pydantic/pull/8678) * Use `is_valid_field` from 1.x for `mypy` plugin by @DanielNoord in [#8738](https://github.com/pydantic/pydantic/pull/8738) * Better-support `mypy` strict equality flag by @dmontagu in [#8799](https://github.com/pydantic/pydantic/pull/8799) * model_json_schema export with Annotated types misses 'required' parameters by @LouisGobert in [#8793](https://github.com/pydantic/pydantic/pull/8793) * Fix default inclusion in `FieldInfo.__repr_args__` by @sydney-runkle in [#8801](https://github.com/pydantic/pydantic/pull/8801) * Fix resolution of forward refs in dataclass base classes that are not present in the subclass module namespace by @matsjoyce-refeyn in [#8751](https://github.com/pydantic/pydantic/pull/8751) * Fix `BaseModel` type annotations to be resolvable by `typing.get_type_hints` by @devmonkey22 in [#7680](https://github.com/pydantic/pydantic/pull/7680) * Fix: allow empty string aliases with `AliasGenerator` by @sydney-runkle in [#8810](https://github.com/pydantic/pydantic/pull/8810) * Fix test along with `date` -> `datetime` timezone assumption fix by @sydney-runkle in [#8823](https://github.com/pydantic/pydantic/pull/8823) * Fix deprecation warning with usage of `ast.Str` by @Viicos in [#8837](https://github.com/pydantic/pydantic/pull/8837) * Add missing `deprecated` decorators by @Viicos in [#8877](https://github.com/pydantic/pydantic/pull/8877) * Fix serialization of `NameEmail` if name includes an email address by @NeevCohen in [#8860](https://github.com/pydantic/pydantic/pull/8860) * Add information about class in error message of schema generation by @Czaki in [#8917](https://github.com/pydantic/pydantic/pull/8917) * Make `TypeAdapter`'s typing compatible with special forms by @adriangb in [#8923](https://github.com/pydantic/pydantic/pull/8923) * Fix issue with config behavior being baked into the ref schema for `enum`s by @dmontagu in [#8920](https://github.com/pydantic/pydantic/pull/8920) * More helpful error re wrong `model_json_schema` usage by @sydney-runkle in [#8928](https://github.com/pydantic/pydantic/pull/8928) * Fix nested discriminated union schema gen, pt 2 by @sydney-runkle in [#8932](https://github.com/pydantic/pydantic/pull/8932) * Fix schema build for nested dataclasses / TypedDicts with discriminators by @sydney-runkle in [#8950](https://github.com/pydantic/pydantic/pull/8950) * Remove unnecessary logic for definitions schema gen with discriminated unions by @sydney-runkle in [#8951](https://github.com/pydantic/pydantic/pull/8951) * Fix handling of optionals in `mypy` plugin by @dmontagu in [#9008](https://github.com/pydantic/pydantic/pull/9008) * Fix `PlainSerializer` usage with std type constructor by @sydney-runkle in [#9031](https://github.com/pydantic/pydantic/pull/9031) * Remove unnecessary warning for config in plugin by @dmontagu in [#9039](https://github.com/pydantic/pydantic/pull/9039) * Fix default value serializing by @NeevCohen in [#9066](https://github.com/pydantic/pydantic/pull/9066) * Fix extra fields check in `Model.__getattr__()` by @NeevCohen in [#9082](https://github.com/pydantic/pydantic/pull/9082) * Fix `ClassVar` forward ref inherited from parent class by @alexmojaki in [#9097](https://github.com/pydantic/pydantic/pull/9097) * fix sequence like validator with strict `True` by @andresliszt in [#8977](https://github.com/pydantic/pydantic/pull/8977) * Improve warning message when a field name shadows a field in a parent model by @chan-vince in [#9105](https://github.com/pydantic/pydantic/pull/9105) * Do not warn about shadowed fields if they are not redefined in a child class by @chan-vince in [#9111](https://github.com/pydantic/pydantic/pull/9111) * Fix discriminated union bug with unsubstituted type var by @sydney-runkle in [#9124](https://github.com/pydantic/pydantic/pull/9124) * Support serialization of `deque` when passed to `Sequence[blah blah blah]` by @sydney-runkle in [#9128](https://github.com/pydantic/pydantic/pull/9128) * Init private attributes from super-types in `model_post_init` by @Viicos in [#9134](https://github.com/pydantic/pydantic/pull/9134) * fix `model_construct` with `validation_alias` by @ornariece in [#9144](https://github.com/pydantic/pydantic/pull/9144) * Ensure json-schema generator handles `Literal` `null` types by @bruno-f-cruz in [#9135](https://github.com/pydantic/pydantic/pull/9135) * **Fixed in v2.7.0**: Fix allow extra generic by @dmontagu in [#9193](https://github.com/pydantic/pydantic/pull/9193) ### New Contributors * @hungtsetse made their first contribution in [#8546](https://github.com/pydantic/pydantic/pull/8546) * @StrawHatDrag0n made their first contribution in [#8583](https://github.com/pydantic/pydantic/pull/8583) * @anci3ntr0ck made their first contribution in [#8642](https://github.com/pydantic/pydantic/pull/8642) * @Holi0317 made their first contribution in [#8650](https://github.com/pydantic/pydantic/pull/8650) * @bluenote10 made their first contribution in [#8651](https://github.com/pydantic/pydantic/pull/8651) * @ADSteele916 made their first contribution in [#8703](https://github.com/pydantic/pydantic/pull/8703) * @musicinmybrain made their first contribution in [#8731](https://github.com/pydantic/pydantic/pull/8731) * @jks15satoshi made their first contribution in [#8706](https://github.com/pydantic/pydantic/pull/8706) * @13sin made their first contribution in [#8734](https://github.com/pydantic/pydantic/pull/8734) * @DanielNoord made their first contribution in [#8738](https://github.com/pydantic/pydantic/pull/8738) * @conradogarciaberrotaran made their first contribution in [#8519](https://github.com/pydantic/pydantic/pull/8519) * @chris-griffin made their first contribution in [#8775](https://github.com/pydantic/pydantic/pull/8775) * @LouisGobert made their first contribution in [#8793](https://github.com/pydantic/pydantic/pull/8793) * @matsjoyce-refeyn made their first contribution in [#8751](https://github.com/pydantic/pydantic/pull/8751) * @devmonkey22 made their first contribution in [#7680](https://github.com/pydantic/pydantic/pull/7680) * @adamency made their first contribution in [#8847](https://github.com/pydantic/pydantic/pull/8847) * @MamfTheKramf made their first contribution in [#8851](https://github.com/pydantic/pydantic/pull/8851) * @ornariece made their first contribution in [#9001](https://github.com/pydantic/pydantic/pull/9001) * @alexeyt101 made their first contribution in [#9004](https://github.com/pydantic/pydantic/pull/9004) * @wannieman98 made their first contribution in [#8947](https://github.com/pydantic/pydantic/pull/8947) * @solidguy7 made their first contribution in [#9062](https://github.com/pydantic/pydantic/pull/9062) * @kloczek made their first contribution in [#9047](https://github.com/pydantic/pydantic/pull/9047) * @jag-k made their first contribution in [#9053](https://github.com/pydantic/pydantic/pull/9053) * @priya-gitTest made their first contribution in [#9088](https://github.com/pydantic/pydantic/pull/9088) * @Youssefares made their first contribution in [#9023](https://github.com/pydantic/pydantic/pull/9023) * @chan-vince made their first contribution in [#9105](https://github.com/pydantic/pydantic/pull/9105) * @bruno-f-cruz made their first contribution in [#9135](https://github.com/pydantic/pydantic/pull/9135) * @Lance-Drane made their first contribution in [#9166](https://github.com/pydantic/pydantic/pull/9166) ## v2.7.0b1 (2024-04-03) Pre-release, see [the GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.7.0b1) for details. ## v2.6.4 (2024-03-12) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.6.4) ### What's Changed #### Fixes * Fix usage of `AliasGenerator` with `computed_field` decorator by @sydney-runkle in [#8806](https://github.com/pydantic/pydantic/pull/8806) * Fix nested discriminated union schema gen, pt 2 by @sydney-runkle in [#8932](https://github.com/pydantic/pydantic/pull/8932) * Fix bug with no_strict_optional=True caused by API deferral by @dmontagu in [#8826](https://github.com/pydantic/pydantic/pull/8826) ## v2.6.3 (2024-02-27) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.6.3) ### What's Changed #### Packaging * Update `pydantic-settings` version in the docs by @hramezani in [#8906](https://github.com/pydantic/pydantic/pull/8906) #### Fixes * Fix discriminated union schema gen bug by @sydney-runkle in [#8904](https://github.com/pydantic/pydantic/pull/8904) ## v2.6.2 (2024-02-23) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.6.2) ### What's Changed #### Packaging * Upgrade to `pydantic-core` 2.16.3 by @sydney-runkle in [#8879](https://github.com/pydantic/pydantic/pull/8879) #### Fixes * 'YYYY-MM-DD' date string coerced to datetime shouldn't infer timezone by @sydney-runkle in [pydantic/pydantic-core#1193](https://github.com/pydantic/pydantic-core/pull/1193) ## v2.6.1 (2024-02-05) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.6.1) ### What's Changed #### Packaging * Upgrade to `pydantic-core` 2.16.2 by @sydney-runkle in [#8717](https://github.com/pydantic/pydantic/pull/8717) #### Fixes * Fix bug with `mypy` plugin and `no_strict_optional = True` by @dmontagu in [#8666](https://github.com/pydantic/pydantic/pull/8666) * Fix `ByteSize` error `type` change by @sydney-runkle in [#8681](https://github.com/pydantic/pydantic/pull/8681) * Fix inheriting `Field` annotations in dataclasses by @sydney-runkle in [#8679](https://github.com/pydantic/pydantic/pull/8679) * Fix regression in core schema generation for indirect definition references by @dmontagu in [#8702](https://github.com/pydantic/pydantic/pull/8702) * Fix unsupported types bug with `PlainValidator` by @sydney-runkle in [#8710](https://github.com/pydantic/pydantic/pull/8710) * Reverting problematic fix from 2.6 release, fixing schema building bug by @sydney-runkle in [#8718](https://github.com/pydantic/pydantic/pull/8718) * Fix warning for tuple of wrong size in `Union` by @davidhewitt in [pydantic/pydantic-core#1174](https://github.com/pydantic/pydantic-core/pull/1174) * Fix `computed_field` JSON serializer `exclude_none` behavior by @sydney-runkle in [pydantic/pydantic-core#1187](https://github.com/pydantic/pydantic-core/pull/1187) ## v2.6.0 (2024-01-23) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.6.0) The code released in v2.6.0 is practically identical to that of v2.6.0b1. ### What's Changed #### Packaging * Check for `email-validator` version >= 2.0 by @commonism in [#6033](https://github.com/pydantic/pydantic/pull/6033) * Upgrade `ruff`` target version to Python 3.8 by @Elkiwa in [#8341](https://github.com/pydantic/pydantic/pull/8341) * Update to `pydantic-extra-types==2.4.1` by @yezz123 in [#8478](https://github.com/pydantic/pydantic/pull/8478) * Update to `pyright==1.1.345` by @Viicos in [#8453](https://github.com/pydantic/pydantic/pull/8453) * Update pydantic-core from 2.14.6 to 2.16.1, significant changes from these updates are described below, full changelog [here](https://github.com/pydantic/pydantic-core/compare/v2.14.6...v2.16.1) #### New Features * Add `NatsDsn` by @ekeew in [#6874](https://github.com/pydantic/pydantic/pull/6874) * Add `ConfigDict.ser_json_inf_nan` by @davidhewitt in [#8159](https://github.com/pydantic/pydantic/pull/8159) * Add `types.OnErrorOmit` by @adriangb in [#8222](https://github.com/pydantic/pydantic/pull/8222) * Support `AliasGenerator` usage by @sydney-runkle in [#8282](https://github.com/pydantic/pydantic/pull/8282) * Add Pydantic People Page to docs by @sydney-runkle in [#8345](https://github.com/pydantic/pydantic/pull/8345) * Support `yyyy-MM-DD` datetime parsing by @sydney-runkle in [#8404](https://github.com/pydantic/pydantic/pull/8404) * Added bits conversions to the `ByteSize` class #8415 by @luca-matei in [#8507](https://github.com/pydantic/pydantic/pull/8507) * Enable json schema creation with type `ByteSize` by @geospackle in [#8537](https://github.com/pydantic/pydantic/pull/8537) * Add `eval_type_backport` to handle union operator and builtin generic subscripting in older Pythons by @alexmojaki in [#8209](https://github.com/pydantic/pydantic/pull/8209) * Add support for `dataclass` fields `init` by @dmontagu in [#8552](https://github.com/pydantic/pydantic/pull/8552) * Implement pickling for `ValidationError` by @davidhewitt in [pydantic/pydantic-core#1119](https://github.com/pydantic/pydantic-core/pull/1119) * Add unified tuple validator that can handle "variadic" tuples via PEP-646 by @dmontagu in [pydantic/pydantic-core#865](https://github.com/pydantic/pydantic-core/pull/865) #### Changes * Drop Python3.7 support by @hramezani in [#7188](https://github.com/pydantic/pydantic/pull/7188) * Drop Python 3.7, and PyPy 3.7 and 3.8 by @davidhewitt in [pydantic/pydantic-core#1129](https://github.com/pydantic/pydantic-core/pull/1129) * Use positional-only `self` in `BaseModel` constructor, so no field name can ever conflict with it by @ariebovenberg in [#8072](https://github.com/pydantic/pydantic/pull/8072) * Make `@validate_call` return a function instead of a custom descriptor - fixes binding issue with inheritance and adds `self/cls` argument to validation errors by @alexmojaki in [#8268](https://github.com/pydantic/pydantic/pull/8268) * Exclude `BaseModel` docstring from JSON schema description by @sydney-runkle in [#8352](https://github.com/pydantic/pydantic/pull/8352) * Introducing `classproperty` decorator for `model_computed_fields` by @Jocelyn-Gas in [#8437](https://github.com/pydantic/pydantic/pull/8437) * Explicitly raise an error if field names clashes with types by @Viicos in [#8243](https://github.com/pydantic/pydantic/pull/8243) * Use stricter serializer for unions of simple types by @alexdrydew [pydantic/pydantic-core#1132](https://github.com/pydantic/pydantic-core/pull/1132) #### Performance * Add Codspeed profiling Actions workflow by @lambertsbennett in [#8054](https://github.com/pydantic/pydantic/pull/8054) * Improve `int` extraction by @samuelcolvin in [pydantic/pydantic-core#1155](https://github.com/pydantic/pydantic-core/pull/1155) * Improve performance of recursion guard by @samuelcolvin in [pydantic/pydantic-core#1156](https://github.com/pydantic/pydantic-core/pull/1156) * `dataclass` serialization speedups by @samuelcolvin in [pydantic/pydantic-core#1162](https://github.com/pydantic/pydantic-core/pull/1162) * Avoid `HashMap` creation when looking up small JSON objects in `LazyIndexMaps` by @samuelcolvin in [pydantic/jiter#55](https://github.com/pydantic/jiter/pull/55) * use hashbrown to speedup python string caching by @davidhewitt in [pydantic/jiter#51](https://github.com/pydantic/jiter/pull/51) * Replace `Peak` with more efficient `Peek` by @davidhewitt in [pydantic/jiter#48](https://github.com/pydantic/jiter/pull/48) #### Fixes * Move `getattr` warning in deprecated `BaseConfig` by @tlambert03 in [#7183](https://github.com/pydantic/pydantic/pull/7183) * Only hash `model_fields`, not whole `__dict__` by @alexmojaki in [#7786](https://github.com/pydantic/pydantic/pull/7786) * Fix mishandling of unions while freezing types in the `mypy` plugin by @dmontagu in [#7411](https://github.com/pydantic/pydantic/pull/7411) * Fix `mypy` error on untyped `ClassVar` by @vincent-hachin-wmx in [#8138](https://github.com/pydantic/pydantic/pull/8138) * Only compare pydantic fields in `BaseModel.__eq__` instead of whole `__dict__` by @QuentinSoubeyranAqemia in [#7825](https://github.com/pydantic/pydantic/pull/7825) * Update `strict` docstring in `model_validate` method. by @LukeTonin in [#8223](https://github.com/pydantic/pydantic/pull/8223) * Fix overload position of `computed_field` by @Viicos in [#8227](https://github.com/pydantic/pydantic/pull/8227) * Fix custom type type casting used in multiple attributes by @ianhfc in [#8066](https://github.com/pydantic/pydantic/pull/8066) * Fix issue not allowing `validate_call` decorator to be dynamically assigned to a class method by @jusexton in [#8249](https://github.com/pydantic/pydantic/pull/8249) * Fix issue `unittest.mock` deprecation warnings by @ibleedicare in [#8262](https://github.com/pydantic/pydantic/pull/8262) * Added tests for the case `JsonValue` contains subclassed primitive values by @jusexton in [#8286](https://github.com/pydantic/pydantic/pull/8286) * Fix `mypy` error on free before validator (classmethod) by @sydney-runkle in [#8285](https://github.com/pydantic/pydantic/pull/8285) * Fix `to_snake` conversion by @jevins09 in [#8316](https://github.com/pydantic/pydantic/pull/8316) * Fix type annotation of `ModelMetaclass.__prepare__` by @slanzmich in [#8305](https://github.com/pydantic/pydantic/pull/8305) * Disallow `config` specification when initializing a `TypeAdapter` when the annotated type has config already by @sydney-runkle in [#8365](https://github.com/pydantic/pydantic/pull/8365) * Fix a naming issue with JSON schema for generics parametrized by recursive type aliases by @dmontagu in [#8389](https://github.com/pydantic/pydantic/pull/8389) * Fix type annotation in pydantic people script by @shenxiangzhuang in [#8402](https://github.com/pydantic/pydantic/pull/8402) * Add support for field `alias` in `dataclass` signature by @NeevCohen in [#8387](https://github.com/pydantic/pydantic/pull/8387) * Fix bug with schema generation with `Field(...)` in a forward ref by @dmontagu in [#8494](https://github.com/pydantic/pydantic/pull/8494) * Fix ordering of keys in `__dict__` with `model_construct` call by @sydney-runkle in [#8500](https://github.com/pydantic/pydantic/pull/8500) * Fix module `path_type` creation when globals does not contain `__name__` by @hramezani in [#8470](https://github.com/pydantic/pydantic/pull/8470) * Fix for namespace issue with dataclasses with `from __future__ import annotations` by @sydney-runkle in [#8513](https://github.com/pydantic/pydantic/pull/8513) * Fix: make function validator types positional-only by @pmmmwh in [#8479](https://github.com/pydantic/pydantic/pull/8479) * Fix usage of `@deprecated` by @Viicos in [#8294](https://github.com/pydantic/pydantic/pull/8294) * Add more support for private attributes in `model_construct` call by @sydney-runkle in [#8525](https://github.com/pydantic/pydantic/pull/8525) * Use a stack for the types namespace by @dmontagu in [#8378](https://github.com/pydantic/pydantic/pull/8378) * Fix schema-building bug with `TypeAliasType` for types with refs by @dmontagu in [#8526](https://github.com/pydantic/pydantic/pull/8526) * Support `pydantic.Field(repr=False)` in dataclasses by @tigeryy2 in [#8511](https://github.com/pydantic/pydantic/pull/8511) * Override `dataclass_transform` behavior for `RootModel` by @Viicos in [#8163](https://github.com/pydantic/pydantic/pull/8163) * Refactor signature generation for simplicity by @sydney-runkle in [#8572](https://github.com/pydantic/pydantic/pull/8572) * Fix ordering bug of PlainValidator annotation by @Anvil in [#8567](https://github.com/pydantic/pydantic/pull/8567) * Fix `exclude_none` for json serialization of `computed_field`s by @sydney-runkle in [pydantic/pydantic-core#1098](https://github.com/pydantic/pydantic-core/pull/1098) * Support yyyy-MM-DD string for datetimes by @sydney-runkle in [pydantic/pydantic-core#1124](https://github.com/pydantic/pydantic-core/pull/1124) * Tweak ordering of definitions in generated schemas by @StrawHatDrag0n in [#8583](https://github.com/pydantic/pydantic/pull/8583) ### New Contributors #### `pydantic` * @ekeew made their first contribution in [#6874](https://github.com/pydantic/pydantic/pull/6874) * @lambertsbennett made their first contribution in [#8054](https://github.com/pydantic/pydantic/pull/8054) * @vincent-hachin-wmx made their first contribution in [#8138](https://github.com/pydantic/pydantic/pull/8138) * @QuentinSoubeyranAqemia made their first contribution in [#7825](https://github.com/pydantic/pydantic/pull/7825) * @ariebovenberg made their first contribution in [#8072](https://github.com/pydantic/pydantic/pull/8072) * @LukeTonin made their first contribution in [#8223](https://github.com/pydantic/pydantic/pull/8223) * @denisart made their first contribution in [#8231](https://github.com/pydantic/pydantic/pull/8231) * @ianhfc made their first contribution in [#8066](https://github.com/pydantic/pydantic/pull/8066) * @eonu made their first contribution in [#8255](https://github.com/pydantic/pydantic/pull/8255) * @amandahla made their first contribution in [#8263](https://github.com/pydantic/pydantic/pull/8263) * @ibleedicare made their first contribution in [#8262](https://github.com/pydantic/pydantic/pull/8262) * @jevins09 made their first contribution in [#8316](https://github.com/pydantic/pydantic/pull/8316) * @cuu508 made their first contribution in [#8322](https://github.com/pydantic/pydantic/pull/8322) * @slanzmich made their first contribution in [#8305](https://github.com/pydantic/pydantic/pull/8305) * @jensenbox made their first contribution in [#8331](https://github.com/pydantic/pydantic/pull/8331) * @szepeviktor made their first contribution in [#8356](https://github.com/pydantic/pydantic/pull/8356) * @Elkiwa made their first contribution in [#8341](https://github.com/pydantic/pydantic/pull/8341) * @parhamfh made their first contribution in [#8395](https://github.com/pydantic/pydantic/pull/8395) * @shenxiangzhuang made their first contribution in [#8402](https://github.com/pydantic/pydantic/pull/8402) * @NeevCohen made their first contribution in [#8387](https://github.com/pydantic/pydantic/pull/8387) * @zby made their first contribution in [#8497](https://github.com/pydantic/pydantic/pull/8497) * @patelnets made their first contribution in [#8491](https://github.com/pydantic/pydantic/pull/8491) * @edwardwli made their first contribution in [#8503](https://github.com/pydantic/pydantic/pull/8503) * @luca-matei made their first contribution in [#8507](https://github.com/pydantic/pydantic/pull/8507) * @Jocelyn-Gas made their first contribution in [#8437](https://github.com/pydantic/pydantic/pull/8437) * @bL34cHig0 made their first contribution in [#8501](https://github.com/pydantic/pydantic/pull/8501) * @tigeryy2 made their first contribution in [#8511](https://github.com/pydantic/pydantic/pull/8511) * @geospackle made their first contribution in [#8537](https://github.com/pydantic/pydantic/pull/8537) * @Anvil made their first contribution in [#8567](https://github.com/pydantic/pydantic/pull/8567) * @hungtsetse made their first contribution in [#8546](https://github.com/pydantic/pydantic/pull/8546) * @StrawHatDrag0n made their first contribution in [#8583](https://github.com/pydantic/pydantic/pull/8583) #### `pydantic-core` * @mariuswinger made their first contribution in [pydantic/pydantic-core#1087](https://github.com/pydantic/pydantic-core/pull/1087) * @adamchainz made their first contribution in [pydantic/pydantic-core#1090](https://github.com/pydantic/pydantic-core/pull/1090) * @akx made their first contribution in [pydantic/pydantic-core#1123](https://github.com/pydantic/pydantic-core/pull/1123) ## v2.6.0b1 (2024-01-19) Pre-release, see [the GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.6.0b1) for details. ## v2.5.3 (2023-12-22) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.5.3) ### What's Changed #### Packaging * uprev `pydantic-core` to 2.14.6 #### Fixes * Fix memory leak with recursive definitions creating reference cycles by @davidhewitt in [pydantic/pydantic-core#1125](https://github.com/pydantic/pydantic-core/pull/1125) ## v2.5.2 (2023-11-22) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.5.2) ### What's Changed #### Packaging * uprev `pydantic-core` to 2.14.5 #### New Features * Add `ConfigDict.ser_json_inf_nan` by @davidhewitt in [#8159](https://github.com/pydantic/pydantic/pull/8159) #### Fixes * Fix validation of `Literal` from JSON keys when used as `dict` key by @sydney-runkle in [pydantic/pydantic-core#1075](https://github.com/pydantic/pydantic-core/pull/1075) * Fix bug re `custom_init` on members of `Union` by @sydney-runkle in [pydantic/pydantic-core#1076](https://github.com/pydantic/pydantic-core/pull/1076) * Fix `JsonValue` `bool` serialization by @sydney-runkle in [#8190](https://github.com/pydantic/pydantic/pull/8159) * Fix handling of unhashable inputs with `Literal` in `Union`s by @sydney-runkle in [pydantic/pydantic-core#1089](https://github.com/pydantic/pydantic-core/pull/1089) ## v2.5.1 (2023-11-15) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.5.1) ### What's Changed #### Packaging * uprev pydantic-core to 2.14.3 by @samuelcolvin in [#8120](https://github.com/pydantic/pydantic/pull/8120) #### Fixes * Fix package description limit by @dmontagu in [#8097](https://github.com/pydantic/pydantic/pull/8097) * Fix `ValidateCallWrapper` error when creating a model which has a @validate_call wrapped field annotation by @sydney-runkle in [#8110](https://github.com/pydantic/pydantic/pull/8110) ## v2.5.0 (2023-11-13) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.5.0) The code released in v2.5.0 is functionally identical to that of v2.5.0b1. ### What's Changed #### Packaging * Update pydantic-core from 2.10.1 to 2.14.1, significant changes from these updates are described below, full changelog [here](https://github.com/pydantic/pydantic-core/compare/v2.10.1...v2.14.1) * Update to `pyright==1.1.335` by @Viicos in [#8075](https://github.com/pydantic/pydantic/pull/8075) #### New Features * Allow plugins to catch non `ValidationError` errors by @adriangb in [#7806](https://github.com/pydantic/pydantic/pull/7806) * Support `__doc__` argument in `create_model()` by @chris-spann in [#7863](https://github.com/pydantic/pydantic/pull/7863) * Expose `regex_engine` flag - meaning you can use with the Rust or Python regex libraries in constraints by @utkini in [#7768](https://github.com/pydantic/pydantic/pull/7768) * Save return type generated from type annotation in `ComputedFieldInfo` by @alexmojaki in [#7889](https://github.com/pydantic/pydantic/pull/7889) * Adopting `ruff` formatter by @Luca-Blight in [#7930](https://github.com/pydantic/pydantic/pull/7930) * Added `validation_error_cause` to config by @zakstucke in [#7626](https://github.com/pydantic/pydantic/pull/7626) * Make path of the item to validate available in plugin by @hramezani in [#7861](https://github.com/pydantic/pydantic/pull/7861) * Add `CallableDiscriminator` and `Tag` by @dmontagu in [#7983](https://github.com/pydantic/pydantic/pull/7983) * `CallableDiscriminator` renamed to `Discriminator` by @dmontagu in [#8047](https://github.com/pydantic/pydantic/pull/8047) * Make union case tags affect union error messages by @dmontagu in [#8001](https://github.com/pydantic/pydantic/pull/8001) * Add `examples` and `json_schema_extra` to `@computed_field` by @alexmojaki in [#8013](https://github.com/pydantic/pydantic/pull/8013) * Add `JsonValue` type by @dmontagu in [#7998](https://github.com/pydantic/pydantic/pull/7998) * Allow `str` as argument to `Discriminator` by @dmontagu in [#8047](https://github.com/pydantic/pydantic/pull/8047) * Add `SchemaSerializer.__reduce__` method to enable pickle serialization by @edoakes in [pydantic/pydantic-core#1006](https://github.com/pydantic/pydantic-core/pull/1006) #### Changes * **Significant Change:** replace `ultra_strict` with new smart union implementation, the way unions are validated has changed significantly to improve performance and correctness, we have worked hard to absolutely minimise the number of cases where behaviour has changed, see the PR for details - by @davidhewitt in [pydantic/pydantic-core#867](https://github.com/pydantic/pydantic-core/pull/867) * Add support for instance method reassignment when `extra='allow'` by @sydney-runkle in [#7683](https://github.com/pydantic/pydantic/pull/7683) * Support JSON schema generation for `Enum` types with no cases by @sydney-runkle in [#7927](https://github.com/pydantic/pydantic/pull/7927) * Warn if a class inherits from `Generic` before `BaseModel` by @alexmojaki in [#7891](https://github.com/pydantic/pydantic/pull/7891) #### Performance * New custom JSON parser, `jiter` by @samuelcolvin in [pydantic/pydantic-core#974](https://github.com/pydantic/pydantic-core/pull/974) * PGO build for MacOS M1 by @samuelcolvin in [pydantic/pydantic-core#1063](https://github.com/pydantic/pydantic-core/pull/1063) * Use `__getattr__` for all package imports, improve import time by @samuelcolvin in [#7947](https://github.com/pydantic/pydantic/pull/7947) #### Fixes * Fix `mypy` issue with subclasses of `RootModel` by @sydney-runkle in [#7677](https://github.com/pydantic/pydantic/pull/7677) * Properly rebuild the `FieldInfo` when a forward ref gets evaluated by @dmontagu in [#7698](https://github.com/pydantic/pydantic/pull/7698) * Fix failure to load `SecretStr` from JSON (regression in v2.4) by @sydney-runkle in [#7729](https://github.com/pydantic/pydantic/pull/7729) * Fix `defer_build` behavior with `TypeAdapter` by @sydney-runkle in [#7736](https://github.com/pydantic/pydantic/pull/7736) * Improve compatibility with legacy `mypy` versions by @dmontagu in [#7742](https://github.com/pydantic/pydantic/pull/7742) * Fix: update `TypeVar` handling when default is not set by @pmmmwh in [#7719](https://github.com/pydantic/pydantic/pull/7719) * Support specification of `strict` on `Enum` type fields by @sydney-runkle in [#7761](https://github.com/pydantic/pydantic/pull/7761) * Wrap `weakref.ref` instead of subclassing to fix `cloudpickle` serialization by @edoakes in [#7780](https://github.com/pydantic/pydantic/pull/7780) * Keep values of private attributes set within `model_post_init` in subclasses by @alexmojaki in [#7775](https://github.com/pydantic/pydantic/pull/7775) * Add more specific type for non-callable `json_schema_extra` by @alexmojaki in [#7803](https://github.com/pydantic/pydantic/pull/7803) * Raise an error when deleting frozen (model) fields by @alexmojaki in [#7800](https://github.com/pydantic/pydantic/pull/7800) * Fix schema sorting bug with default values by @sydney-runkle in [#7817](https://github.com/pydantic/pydantic/pull/7817) * Use generated alias for aliases that are not specified otherwise by @alexmojaki in [#7802](https://github.com/pydantic/pydantic/pull/7802) * Support `strict` specification for `UUID` types by @sydney-runkle in [#7865](https://github.com/pydantic/pydantic/pull/7865) * JSON schema: fix extra parameter handling by @me-and in [#7810](https://github.com/pydantic/pydantic/pull/7810) * Fix: support `pydantic.Field(kw_only=True)` with inherited dataclasses by @PrettyWood in [#7827](https://github.com/pydantic/pydantic/pull/7827) * Support `validate_call` decorator for methods in classes with `__slots__` by @sydney-runkle in [#7883](https://github.com/pydantic/pydantic/pull/7883) * Fix pydantic dataclass problem with `dataclasses.field` default by @hramezani in [#7898](https://github.com/pydantic/pydantic/pull/7898) * Fix schema generation for generics with union type bounds by @sydney-runkle in [#7899](https://github.com/pydantic/pydantic/pull/7899) * Fix version for `importlib_metadata` on python 3.7 by @sydney-runkle in [#7904](https://github.com/pydantic/pydantic/pull/7904) * Support `|` operator (Union) in PydanticRecursiveRef by @alexmojaki in [#7892](https://github.com/pydantic/pydantic/pull/7892) * Fix `display_as_type` for `TypeAliasType` in python 3.12 by @dmontagu in [#7929](https://github.com/pydantic/pydantic/pull/7929) * Add support for `NotRequired` generics in `TypedDict` by @sydney-runkle in [#7932](https://github.com/pydantic/pydantic/pull/7932) * Make generic `TypeAliasType` specifications produce different schema definitions by @alexdrydew in [#7893](https://github.com/pydantic/pydantic/pull/7893) * Added fix for signature of inherited dataclass by @howsunjow in [#7925](https://github.com/pydantic/pydantic/pull/7925) * Make the model name generation more robust in JSON schema by @joakimnordling in [#7881](https://github.com/pydantic/pydantic/pull/7881) * Fix plurals in validation error messages (in tests) by @Iipin in [#7972](https://github.com/pydantic/pydantic/pull/7972) * `PrivateAttr` is passed from `Annotated` default position by @tabassco in [#8004](https://github.com/pydantic/pydantic/pull/8004) * Don't decode bytes (which may not be UTF8) when displaying SecretBytes by @alexmojaki in [#8012](https://github.com/pydantic/pydantic/pull/8012) * Use `classmethod` instead of `classmethod[Any, Any, Any]` by @Mr-Pepe in [#7979](https://github.com/pydantic/pydantic/pull/7979) * Clearer error on invalid Plugin by @samuelcolvin in [#8023](https://github.com/pydantic/pydantic/pull/8023) * Correct pydantic dataclasses import by @samuelcolvin in [#8027](https://github.com/pydantic/pydantic/pull/8027) * Fix misbehavior for models referencing redefined type aliases by @dmontagu in [#8050](https://github.com/pydantic/pydantic/pull/8050) * Fix `Optional` field with `validate_default` only performing one field validation by @sydney-runkle in [pydantic/pydantic-core#1002](https://github.com/pydantic/pydantic-core/pull/1002) * Fix `definition-ref` bug with `Dict` keys by @sydney-runkle in [pydantic/pydantic-core#1014](https://github.com/pydantic/pydantic-core/pull/1014) * Fix bug allowing validation of `bool` types with `coerce_numbers_to_str=True` by @sydney-runkle in [pydantic/pydantic-core#1017](https://github.com/pydantic/pydantic-core/pull/1017) * Don't accept `NaN` in float and decimal constraints by @davidhewitt in [pydantic/pydantic-core#1037](https://github.com/pydantic/pydantic-core/pull/1037) * Add `lax_str` and `lax_int` support for enum values not inherited from str/int by @michaelhly in [pydantic/pydantic-core#1015](https://github.com/pydantic/pydantic-core/pull/1015) * Support subclasses in lists in `Union` of `List` types by @sydney-runkle in [pydantic/pydantic-core#1039](https://github.com/pydantic/pydantic-core/pull/1039) * Allow validation against `max_digits` and `decimals` to pass if normalized or non-normalized input is valid by @sydney-runkle in [pydantic/pydantic-core#1049](https://github.com/pydantic/pydantic-core/pull/1049) * Fix: proper pluralization in `ValidationError` messages by @Iipin in [pydantic/pydantic-core#1050](https://github.com/pydantic/pydantic-core/pull/1050) * Disallow the string `'-'` as `datetime` input by @davidhewitt in [pydantic/speedate#52](https://github.com/pydantic/speedate/pull/52) & [pydantic/pydantic-core#1060](https://github.com/pydantic/pydantic-core/pull/1060) * Fix: NaN and Inf float serialization by @davidhewitt in [pydantic/pydantic-core#1062](https://github.com/pydantic/pydantic-core/pull/1062) * Restore manylinux-compatible PGO builds by @davidhewitt in [pydantic/pydantic-core#1068](https://github.com/pydantic/pydantic-core/pull/1068) ### New Contributors #### `pydantic` * @schneebuzz made their first contribution in [#7699](https://github.com/pydantic/pydantic/pull/7699) * @edoakes made their first contribution in [#7780](https://github.com/pydantic/pydantic/pull/7780) * @alexmojaki made their first contribution in [#7775](https://github.com/pydantic/pydantic/pull/7775) * @NickG123 made their first contribution in [#7751](https://github.com/pydantic/pydantic/pull/7751) * @gowthamgts made their first contribution in [#7830](https://github.com/pydantic/pydantic/pull/7830) * @jamesbraza made their first contribution in [#7848](https://github.com/pydantic/pydantic/pull/7848) * @laundmo made their first contribution in [#7850](https://github.com/pydantic/pydantic/pull/7850) * @rahmatnazali made their first contribution in [#7870](https://github.com/pydantic/pydantic/pull/7870) * @waterfountain1996 made their first contribution in [#7878](https://github.com/pydantic/pydantic/pull/7878) * @chris-spann made their first contribution in [#7863](https://github.com/pydantic/pydantic/pull/7863) * @me-and made their first contribution in [#7810](https://github.com/pydantic/pydantic/pull/7810) * @utkini made their first contribution in [#7768](https://github.com/pydantic/pydantic/pull/7768) * @bn-l made their first contribution in [#7744](https://github.com/pydantic/pydantic/pull/7744) * @alexdrydew made their first contribution in [#7893](https://github.com/pydantic/pydantic/pull/7893) * @Luca-Blight made their first contribution in [#7930](https://github.com/pydantic/pydantic/pull/7930) * @howsunjow made their first contribution in [#7925](https://github.com/pydantic/pydantic/pull/7925) * @joakimnordling made their first contribution in [#7881](https://github.com/pydantic/pydantic/pull/7881) * @icfly2 made their first contribution in [#7976](https://github.com/pydantic/pydantic/pull/7976) * @Yummy-Yums made their first contribution in [#8003](https://github.com/pydantic/pydantic/pull/8003) * @Iipin made their first contribution in [#7972](https://github.com/pydantic/pydantic/pull/7972) * @tabassco made their first contribution in [#8004](https://github.com/pydantic/pydantic/pull/8004) * @Mr-Pepe made their first contribution in [#7979](https://github.com/pydantic/pydantic/pull/7979) * @0x00cl made their first contribution in [#8010](https://github.com/pydantic/pydantic/pull/8010) * @barraponto made their first contribution in [#8032](https://github.com/pydantic/pydantic/pull/8032) #### `pydantic-core` * @sisp made their first contribution in [pydantic/pydantic-core#995](https://github.com/pydantic/pydantic-core/pull/995) * @michaelhly made their first contribution in [pydantic/pydantic-core#1015](https://github.com/pydantic/pydantic-core/pull/1015) ## v2.5.0b1 (2023-11-09) Pre-release, see [the GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.5.0b1) for details. ## v2.4.2 (2023-09-27) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.4.2) ### What's Changed #### Fixes * Fix bug with JSON schema for sequence of discriminated union by @dmontagu in [#7647](https://github.com/pydantic/pydantic/pull/7647) * Fix schema references in discriminated unions by @adriangb in [#7646](https://github.com/pydantic/pydantic/pull/7646) * Fix json schema generation for recursive models by @adriangb in [#7653](https://github.com/pydantic/pydantic/pull/7653) * Fix `models_json_schema` for generic models by @adriangb in [#7654](https://github.com/pydantic/pydantic/pull/7654) * Fix xfailed test for generic model signatures by @adriangb in [#7658](https://github.com/pydantic/pydantic/pull/7658) ### New Contributors * @austinorr made their first contribution in [#7657](https://github.com/pydantic/pydantic/pull/7657) * @peterHoburg made their first contribution in [#7670](https://github.com/pydantic/pydantic/pull/7670) ## v2.4.1 (2023-09-26) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.4.1) ### What's Changed #### Packaging * Update pydantic-core to 2.10.1 by @davidhewitt in [#7633](https://github.com/pydantic/pydantic/pull/7633) #### Fixes * Serialize unsubstituted type vars as `Any` by @adriangb in [#7606](https://github.com/pydantic/pydantic/pull/7606) * Remove schema building caches by @adriangb in [#7624](https://github.com/pydantic/pydantic/pull/7624) * Fix an issue where JSON schema extras weren't JSON encoded by @dmontagu in [#7625](https://github.com/pydantic/pydantic/pull/7625) ## v2.4.0 (2023-09-22) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.4.0) ### What's Changed #### Packaging * Update pydantic-core to 2.10.0 by @samuelcolvin in [#7542](https://github.com/pydantic/pydantic/pull/7542) #### New Features * Add `Base64Url` types by @dmontagu in [#7286](https://github.com/pydantic/pydantic/pull/7286) * Implement optional `number` to `str` coercion by @lig in [#7508](https://github.com/pydantic/pydantic/pull/7508) * Allow access to `field_name` and `data` in all validators if there is data and a field name by @samuelcolvin in [#7542](https://github.com/pydantic/pydantic/pull/7542) * Add `BaseModel.model_validate_strings` and `TypeAdapter.validate_strings` by @hramezani in [#7552](https://github.com/pydantic/pydantic/pull/7552) * Add Pydantic `plugins` experimental implementation by @lig @samuelcolvin and @Kludex in [#6820](https://github.com/pydantic/pydantic/pull/6820) #### Changes * Do not override `model_post_init` in subclass with private attrs by @Viicos in [#7302](https://github.com/pydantic/pydantic/pull/7302) * Make fields with defaults not required in the serialization schema by default by @dmontagu in [#7275](https://github.com/pydantic/pydantic/pull/7275) * Mark `Extra` as deprecated by @disrupted in [#7299](https://github.com/pydantic/pydantic/pull/7299) * Make `EncodedStr` a dataclass by @Kludex in [#7396](https://github.com/pydantic/pydantic/pull/7396) * Move `annotated_handlers` to be public by @samuelcolvin in [#7569](https://github.com/pydantic/pydantic/pull/7569) #### Performance * Simplify flattening and inlining of `CoreSchema` by @adriangb in [#7523](https://github.com/pydantic/pydantic/pull/7523) * Remove unused copies in `CoreSchema` walking by @adriangb in [#7528](https://github.com/pydantic/pydantic/pull/7528) * Add caches for collecting definitions and invalid schemas from a CoreSchema by @adriangb in [#7527](https://github.com/pydantic/pydantic/pull/7527) * Eagerly resolve discriminated unions and cache cases where we can't by @adriangb in [#7529](https://github.com/pydantic/pydantic/pull/7529) * Replace `dict.get` and `dict.setdefault` with more verbose versions in `CoreSchema` building hot paths by @adriangb in [#7536](https://github.com/pydantic/pydantic/pull/7536) * Cache invalid `CoreSchema` discovery by @adriangb in [#7535](https://github.com/pydantic/pydantic/pull/7535) * Allow disabling `CoreSchema` validation for faster startup times by @adriangb in [#7565](https://github.com/pydantic/pydantic/pull/7565) #### Fixes * Fix config detection for `TypedDict` from grandparent classes by @dmontagu in [#7272](https://github.com/pydantic/pydantic/pull/7272) * Fix hash function generation for frozen models with unusual MRO by @dmontagu in [#7274](https://github.com/pydantic/pydantic/pull/7274) * Make `strict` config overridable in field for Path by @hramezani in [#7281](https://github.com/pydantic/pydantic/pull/7281) * Use `ser_json_` on default in `GenerateJsonSchema` by @Kludex in [#7269](https://github.com/pydantic/pydantic/pull/7269) * Adding a check that alias is validated as an identifier for Python by @andree0 in [#7319](https://github.com/pydantic/pydantic/pull/7319) * Raise an error when computed field overrides field by @sydney-runkle in [#7346](https://github.com/pydantic/pydantic/pull/7346) * Fix applying `SkipValidation` to referenced schemas by @adriangb in [#7381](https://github.com/pydantic/pydantic/pull/7381) * Enforce behavior of private attributes having double leading underscore by @lig in [#7265](https://github.com/pydantic/pydantic/pull/7265) * Standardize `__get_pydantic_core_schema__` signature by @hramezani in [#7415](https://github.com/pydantic/pydantic/pull/7415) * Fix generic dataclass fields mutation bug (when using `TypeAdapter`) by @sydney-runkle in [#7435](https://github.com/pydantic/pydantic/pull/7435) * Fix `TypeError` on `model_validator` in `wrap` mode by @pmmmwh in [#7496](https://github.com/pydantic/pydantic/pull/7496) * Improve enum error message by @hramezani in [#7506](https://github.com/pydantic/pydantic/pull/7506) * Make `repr` work for instances that failed initialization when handling `ValidationError`s by @dmontagu in [#7439](https://github.com/pydantic/pydantic/pull/7439) * Fixed a regular expression denial of service issue by limiting whitespaces by @prodigysml in [#7360](https://github.com/pydantic/pydantic/pull/7360) * Fix handling of `UUID` values having `UUID.version=None` by @lig in [#7566](https://github.com/pydantic/pydantic/pull/7566) * Fix `__iter__` returning private `cached_property` info by @sydney-runkle in [#7570](https://github.com/pydantic/pydantic/pull/7570) * Improvements to version info message by @samuelcolvin in [#7594](https://github.com/pydantic/pydantic/pull/7594) ### New Contributors * @15498th made their first contribution in [#7238](https://github.com/pydantic/pydantic/pull/7238) * @GabrielCappelli made their first contribution in [#7213](https://github.com/pydantic/pydantic/pull/7213) * @tobni made their first contribution in [#7184](https://github.com/pydantic/pydantic/pull/7184) * @redruin1 made their first contribution in [#7282](https://github.com/pydantic/pydantic/pull/7282) * @FacerAin made their first contribution in [#7288](https://github.com/pydantic/pydantic/pull/7288) * @acdha made their first contribution in [#7297](https://github.com/pydantic/pydantic/pull/7297) * @andree0 made their first contribution in [#7319](https://github.com/pydantic/pydantic/pull/7319) * @gordonhart made their first contribution in [#7375](https://github.com/pydantic/pydantic/pull/7375) * @pmmmwh made their first contribution in [#7496](https://github.com/pydantic/pydantic/pull/7496) * @disrupted made their first contribution in [#7299](https://github.com/pydantic/pydantic/pull/7299) * @prodigysml made their first contribution in [#7360](https://github.com/pydantic/pydantic/pull/7360) ## v2.3.0 (2023-08-23) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.3.0) * 🔥 Remove orphaned changes file from repo by @lig in [#7168](https://github.com/pydantic/pydantic/pull/7168) * Add copy button on documentation by @Kludex in [#7190](https://github.com/pydantic/pydantic/pull/7190) * Fix docs on JSON type by @Kludex in [#7189](https://github.com/pydantic/pydantic/pull/7189) * Update mypy 1.5.0 to 1.5.1 in CI by @hramezani in [#7191](https://github.com/pydantic/pydantic/pull/7191) * fix download links badge by @samuelcolvin in [#7200](https://github.com/pydantic/pydantic/pull/7200) * add 2.2.1 to changelog by @samuelcolvin in [#7212](https://github.com/pydantic/pydantic/pull/7212) * Make ModelWrapValidator protocols generic by @dmontagu in [#7154](https://github.com/pydantic/pydantic/pull/7154) * Correct `Field(..., exclude: bool)` docs by @samuelcolvin in [#7214](https://github.com/pydantic/pydantic/pull/7214) * Make shadowing attributes a warning instead of an error by @adriangb in [#7193](https://github.com/pydantic/pydantic/pull/7193) * Document `Base64Str` and `Base64Bytes` by @Kludex in [#7192](https://github.com/pydantic/pydantic/pull/7192) * Fix `config.defer_build` for serialization first cases by @samuelcolvin in [#7024](https://github.com/pydantic/pydantic/pull/7024) * clean Model docstrings in JSON Schema by @samuelcolvin in [#7210](https://github.com/pydantic/pydantic/pull/7210) * fix [#7228](https://github.com/pydantic/pydantic/pull/7228) (typo): docs in `validators.md` to correct `validate_default` kwarg by @lmmx in [#7229](https://github.com/pydantic/pydantic/pull/7229) * ✅ Implement `tzinfo.fromutc` method for `TzInfo` in `pydantic-core` by @lig in [#7019](https://github.com/pydantic/pydantic/pull/7019) * Support `__get_validators__` by @hramezani in [#7197](https://github.com/pydantic/pydantic/pull/7197) ## v2.2.1 (2023-08-18) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.2.1) * Make `xfail`ing test for root model extra stop `xfail`ing by @dmontagu in [#6937](https://github.com/pydantic/pydantic/pull/6937) * Optimize recursion detection by stopping on the second visit for the same object by @mciucu in [#7160](https://github.com/pydantic/pydantic/pull/7160) * fix link in docs by @tlambert03 in [#7166](https://github.com/pydantic/pydantic/pull/7166) * Replace MiMalloc w/ default allocator by @adriangb in [pydantic/pydantic-core#900](https://github.com/pydantic/pydantic-core/pull/900) * Bump pydantic-core to 2.6.1 and prepare 2.2.1 release by @adriangb in [#7176](https://github.com/pydantic/pydantic/pull/7176) ## v2.2.0 (2023-08-17) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.2.0) * Split "pipx install" setup command into two commands on the documentation site by @nomadmtb in [#6869](https://github.com/pydantic/pydantic/pull/6869) * Deprecate `Field.include` by @hramezani in [#6852](https://github.com/pydantic/pydantic/pull/6852) * Fix typo in default factory error msg by @hramezani in [#6880](https://github.com/pydantic/pydantic/pull/6880) * Simplify handling of typing.Annotated in GenerateSchema by @dmontagu in [#6887](https://github.com/pydantic/pydantic/pull/6887) * Re-enable fastapi tests in CI by @dmontagu in [#6883](https://github.com/pydantic/pydantic/pull/6883) * Make it harder to hit collisions with json schema defrefs by @dmontagu in [#6566](https://github.com/pydantic/pydantic/pull/6566) * Cleaner error for invalid input to `Path` fields by @samuelcolvin in [#6903](https://github.com/pydantic/pydantic/pull/6903) * :memo: support Coordinate Type by @yezz123 in [#6906](https://github.com/pydantic/pydantic/pull/6906) * Fix `ForwardRef` wrapper for py 3.10.0 (shim until bpo-45166) by @randomir in [#6919](https://github.com/pydantic/pydantic/pull/6919) * Fix misbehavior related to copying of RootModel by @dmontagu in [#6918](https://github.com/pydantic/pydantic/pull/6918) * Fix issue with recursion error caused by ParamSpec by @dmontagu in [#6923](https://github.com/pydantic/pydantic/pull/6923) * Add section about Constrained classes to the Migration Guide by @Kludex in [#6924](https://github.com/pydantic/pydantic/pull/6924) * Use `main` branch for badge links by @Viicos in [#6925](https://github.com/pydantic/pydantic/pull/6925) * Add test for v1/v2 Annotated discrepancy by @carlbordum in [#6926](https://github.com/pydantic/pydantic/pull/6926) * Make the v1 mypy plugin work with both v1 and v2 by @dmontagu in [#6921](https://github.com/pydantic/pydantic/pull/6921) * Fix issue where generic models couldn't be parametrized with BaseModel by @dmontagu in [#6933](https://github.com/pydantic/pydantic/pull/6933) * Remove xfail for discriminated union with alias by @dmontagu in [#6938](https://github.com/pydantic/pydantic/pull/6938) * add field_serializer to computed_field by @andresliszt in [#6965](https://github.com/pydantic/pydantic/pull/6965) * Use union_schema with Type[Union[...]] by @JeanArhancet in [#6952](https://github.com/pydantic/pydantic/pull/6952) * Fix inherited typeddict attributes / config by @adriangb in [#6981](https://github.com/pydantic/pydantic/pull/6981) * fix dataclass annotated before validator called twice by @davidhewitt in [#6998](https://github.com/pydantic/pydantic/pull/6998) * Update test-fastapi deselected tests by @hramezani in [#7014](https://github.com/pydantic/pydantic/pull/7014) * Fix validator doc format by @hramezani in [#7015](https://github.com/pydantic/pydantic/pull/7015) * Fix typo in docstring of model_json_schema by @AdamVinch-Federated in [#7032](https://github.com/pydantic/pydantic/pull/7032) * remove unused "type ignores" with pyright by @samuelcolvin in [#7026](https://github.com/pydantic/pydantic/pull/7026) * Add benchmark representing FastAPI startup time by @adriangb in [#7030](https://github.com/pydantic/pydantic/pull/7030) * Fix json_encoders for Enum subclasses by @adriangb in [#7029](https://github.com/pydantic/pydantic/pull/7029) * Update docstring of `ser_json_bytes` regarding base64 encoding by @Viicos in [#7052](https://github.com/pydantic/pydantic/pull/7052) * Allow `@validate_call` to work on async methods by @adriangb in [#7046](https://github.com/pydantic/pydantic/pull/7046) * Fix: mypy error with `Settings` and `SettingsConfigDict` by @JeanArhancet in [#7002](https://github.com/pydantic/pydantic/pull/7002) * Fix some typos (repeated words and it's/its) by @eumiro in [#7063](https://github.com/pydantic/pydantic/pull/7063) * Fix the typo in docstring by @harunyasar in [#7062](https://github.com/pydantic/pydantic/pull/7062) * Docs: Fix broken URL in the pydantic-settings package recommendation by @swetjen in [#6995](https://github.com/pydantic/pydantic/pull/6995) * Handle constraints being applied to schemas that don't accept it by @adriangb in [#6951](https://github.com/pydantic/pydantic/pull/6951) * Replace almost_equal_floats with math.isclose by @eumiro in [#7082](https://github.com/pydantic/pydantic/pull/7082) * bump pydantic-core to 2.5.0 by @davidhewitt in [#7077](https://github.com/pydantic/pydantic/pull/7077) * Add `short_version` and use it in links by @hramezani in [#7115](https://github.com/pydantic/pydantic/pull/7115) * 📝 Add usage link to `RootModel` by @Kludex in [#7113](https://github.com/pydantic/pydantic/pull/7113) * Revert "Fix default port for mongosrv DSNs (#6827)" by @Kludex in [#7116](https://github.com/pydantic/pydantic/pull/7116) * Clarify validate_default and _Unset handling in usage docs and migration guide by @benbenbang in [#6950](https://github.com/pydantic/pydantic/pull/6950) * Tweak documentation of `Field.exclude` by @Viicos in [#7086](https://github.com/pydantic/pydantic/pull/7086) * Do not require `validate_assignment` to use `Field.frozen` by @Viicos in [#7103](https://github.com/pydantic/pydantic/pull/7103) * tweaks to `_core_utils` by @samuelcolvin in [#7040](https://github.com/pydantic/pydantic/pull/7040) * Make DefaultDict working with set by @hramezani in [#7126](https://github.com/pydantic/pydantic/pull/7126) * Don't always require typing.Generic as a base for partially parametrized models by @dmontagu in [#7119](https://github.com/pydantic/pydantic/pull/7119) * Fix issue with JSON schema incorrectly using parent class core schema by @dmontagu in [#7020](https://github.com/pydantic/pydantic/pull/7020) * Fix xfailed test related to TypedDict and alias_generator by @dmontagu in [#6940](https://github.com/pydantic/pydantic/pull/6940) * Improve error message for NameEmail by @dmontagu in [#6939](https://github.com/pydantic/pydantic/pull/6939) * Fix generic computed fields by @dmontagu in [#6988](https://github.com/pydantic/pydantic/pull/6988) * Reflect namedtuple default values during validation by @dmontagu in [#7144](https://github.com/pydantic/pydantic/pull/7144) * Update dependencies, fix pydantic-core usage, fix CI issues by @dmontagu in [#7150](https://github.com/pydantic/pydantic/pull/7150) * Add mypy 1.5.0 by @hramezani in [#7118](https://github.com/pydantic/pydantic/pull/7118) * Handle non-json native enum values by @adriangb in [#7056](https://github.com/pydantic/pydantic/pull/7056) * document `round_trip` in Json type documentation by @jc-louis in [#7137](https://github.com/pydantic/pydantic/pull/7137) * Relax signature checks to better support builtins and C extension functions as validators by @adriangb in [#7101](https://github.com/pydantic/pydantic/pull/7101) * add union_mode='left_to_right' by @davidhewitt in [#7151](https://github.com/pydantic/pydantic/pull/7151) * Include an error message hint for inherited ordering by @yvalencia91 in [#7124](https://github.com/pydantic/pydantic/pull/7124) * Fix one docs link and resolve some warnings for two others by @dmontagu in [#7153](https://github.com/pydantic/pydantic/pull/7153) * Include Field extra keys name in warning by @hramezani in [#7136](https://github.com/pydantic/pydantic/pull/7136) ## v2.1.1 (2023-07-25) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.1.1) * Skip FieldInfo merging when unnecessary by @dmontagu in [#6862](https://github.com/pydantic/pydantic/pull/6862) ## v2.1.0 (2023-07-25) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.1.0) * Add `StringConstraints` for use as Annotated metadata by @adriangb in [#6605](https://github.com/pydantic/pydantic/pull/6605) * Try to fix intermittently failing CI by @adriangb in [#6683](https://github.com/pydantic/pydantic/pull/6683) * Remove redundant example of optional vs default. by @ehiggs-deliverect in [#6676](https://github.com/pydantic/pydantic/pull/6676) * Docs update by @samuelcolvin in [#6692](https://github.com/pydantic/pydantic/pull/6692) * Remove the Validate always section in validator docs by @adriangb in [#6679](https://github.com/pydantic/pydantic/pull/6679) * Fix recursion error in json schema generation by @adriangb in [#6720](https://github.com/pydantic/pydantic/pull/6720) * Fix incorrect subclass check for secretstr by @AlexVndnblcke in [#6730](https://github.com/pydantic/pydantic/pull/6730) * update pdm / pdm lockfile to 2.8.0 by @davidhewitt in [#6714](https://github.com/pydantic/pydantic/pull/6714) * unpin pdm on more CI jobs by @davidhewitt in [#6755](https://github.com/pydantic/pydantic/pull/6755) * improve source locations for auxiliary packages in docs by @davidhewitt in [#6749](https://github.com/pydantic/pydantic/pull/6749) * Assume builtins don't accept an info argument by @adriangb in [#6754](https://github.com/pydantic/pydantic/pull/6754) * Fix bug where calling `help(BaseModelSubclass)` raises errors by @hramezani in [#6758](https://github.com/pydantic/pydantic/pull/6758) * Fix mypy plugin handling of `@model_validator(mode="after")` by @ljodal in [#6753](https://github.com/pydantic/pydantic/pull/6753) * update pydantic-core to 2.3.1 by @davidhewitt in [#6756](https://github.com/pydantic/pydantic/pull/6756) * Mypy plugin for settings by @hramezani in [#6760](https://github.com/pydantic/pydantic/pull/6760) * Use `contentSchema` keyword for JSON schema by @dmontagu in [#6715](https://github.com/pydantic/pydantic/pull/6715) * fast-path checking finite decimals by @davidhewitt in [#6769](https://github.com/pydantic/pydantic/pull/6769) * Docs update by @samuelcolvin in [#6771](https://github.com/pydantic/pydantic/pull/6771) * Improve json schema doc by @hramezani in [#6772](https://github.com/pydantic/pydantic/pull/6772) * Update validator docs by @adriangb in [#6695](https://github.com/pydantic/pydantic/pull/6695) * Fix typehint for wrap validator by @dmontagu in [#6788](https://github.com/pydantic/pydantic/pull/6788) * 🐛 Fix validation warning for unions of Literal and other type by @lig in [#6628](https://github.com/pydantic/pydantic/pull/6628) * Update documentation for generics support in V2 by @tpdorsey in [#6685](https://github.com/pydantic/pydantic/pull/6685) * add pydantic-core build info to `version_info()` by @samuelcolvin in [#6785](https://github.com/pydantic/pydantic/pull/6785) * Fix pydantic dataclasses that use slots with default values by @dmontagu in [#6796](https://github.com/pydantic/pydantic/pull/6796) * Fix inheritance of hash function for frozen models by @dmontagu in [#6789](https://github.com/pydantic/pydantic/pull/6789) * ✨ Add `SkipJsonSchema` annotation by @Kludex in [#6653](https://github.com/pydantic/pydantic/pull/6653) * Error if an invalid field name is used with Field by @dmontagu in [#6797](https://github.com/pydantic/pydantic/pull/6797) * Add `GenericModel` to `MOVED_IN_V2` by @adriangb in [#6776](https://github.com/pydantic/pydantic/pull/6776) * Remove unused code from `docs/usage/types/custom.md` by @hramezani in [#6803](https://github.com/pydantic/pydantic/pull/6803) * Fix `float` -> `Decimal` coercion precision loss by @adriangb in [#6810](https://github.com/pydantic/pydantic/pull/6810) * remove email validation from the north star benchmark by @davidhewitt in [#6816](https://github.com/pydantic/pydantic/pull/6816) * Fix link to mypy by @progsmile in [#6824](https://github.com/pydantic/pydantic/pull/6824) * Improve initialization hooks example by @hramezani in [#6822](https://github.com/pydantic/pydantic/pull/6822) * Fix default port for mongosrv DSNs by @dmontagu in [#6827](https://github.com/pydantic/pydantic/pull/6827) * Improve API documentation, in particular more links between usage and API docs by @samuelcolvin in [#6780](https://github.com/pydantic/pydantic/pull/6780) * update pydantic-core to 2.4.0 by @davidhewitt in [#6831](https://github.com/pydantic/pydantic/pull/6831) * Fix `annotated_types.MaxLen` validator for custom sequence types by @ImogenBits in [#6809](https://github.com/pydantic/pydantic/pull/6809) * Update V1 by @hramezani in [#6833](https://github.com/pydantic/pydantic/pull/6833) * Make it so callable JSON schema extra works by @dmontagu in [#6798](https://github.com/pydantic/pydantic/pull/6798) * Fix serialization issue with `InstanceOf` by @dmontagu in [#6829](https://github.com/pydantic/pydantic/pull/6829) * Add back support for `json_encoders` by @adriangb in [#6811](https://github.com/pydantic/pydantic/pull/6811) * Update field annotations when building the schema by @dmontagu in [#6838](https://github.com/pydantic/pydantic/pull/6838) * Use `WeakValueDictionary` to fix generic memory leak by @dmontagu in [#6681](https://github.com/pydantic/pydantic/pull/6681) * Add `config.defer_build` to optionally make model building lazy by @samuelcolvin in [#6823](https://github.com/pydantic/pydantic/pull/6823) * delegate `UUID` serialization to pydantic-core by @davidhewitt in [#6850](https://github.com/pydantic/pydantic/pull/6850) * Update `json_encoders` docs by @adriangb in [#6848](https://github.com/pydantic/pydantic/pull/6848) * Fix error message for `staticmethod`/`classmethod` order with validate_call by @dmontagu in [#6686](https://github.com/pydantic/pydantic/pull/6686) * Improve documentation for `Config` by @samuelcolvin in [#6847](https://github.com/pydantic/pydantic/pull/6847) * Update serialization doc to mention `Field.exclude` takes priority over call-time `include/exclude` by @hramezani in [#6851](https://github.com/pydantic/pydantic/pull/6851) * Allow customizing core schema generation by making `GenerateSchema` public by @adriangb in [#6737](https://github.com/pydantic/pydantic/pull/6737) ## v2.0.3 (2023-07-05) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.0.3) * Mention PyObject (v1) moving to ImportString (v2) in migration doc by @slafs in [#6456](https://github.com/pydantic/pydantic/pull/6456) * Fix release-tweet CI by @Kludex in [#6461](https://github.com/pydantic/pydantic/pull/6461) * Revise the section on required / optional / nullable fields. by @ybressler in [#6468](https://github.com/pydantic/pydantic/pull/6468) * Warn if a type hint is not in fact a type by @adriangb in [#6479](https://github.com/pydantic/pydantic/pull/6479) * Replace TransformSchema with GetPydanticSchema by @dmontagu in [#6484](https://github.com/pydantic/pydantic/pull/6484) * Fix the un-hashability of various annotation types, for use in caching generic containers by @dmontagu in [#6480](https://github.com/pydantic/pydantic/pull/6480) * PYD-164: Rework custom types docs by @adriangb in [#6490](https://github.com/pydantic/pydantic/pull/6490) * Fix ci by @adriangb in [#6507](https://github.com/pydantic/pydantic/pull/6507) * Fix forward ref in generic by @adriangb in [#6511](https://github.com/pydantic/pydantic/pull/6511) * Fix generation of serialization JSON schemas for core_schema.ChainSchema by @dmontagu in [#6515](https://github.com/pydantic/pydantic/pull/6515) * Document the change in `Field.alias` behavior in Pydantic V2 by @hramezani in [#6508](https://github.com/pydantic/pydantic/pull/6508) * Give better error message attempting to compute the json schema of a model with undefined fields by @dmontagu in [#6519](https://github.com/pydantic/pydantic/pull/6519) * Document `alias_priority` by @tpdorsey in [#6520](https://github.com/pydantic/pydantic/pull/6520) * Add redirect for types documentation by @tpdorsey in [#6513](https://github.com/pydantic/pydantic/pull/6513) * Allow updating docs without release by @samuelcolvin in [#6551](https://github.com/pydantic/pydantic/pull/6551) * Ensure docs tests always run in the right folder by @dmontagu in [#6487](https://github.com/pydantic/pydantic/pull/6487) * Defer evaluation of return type hints for serializer functions by @dmontagu in [#6516](https://github.com/pydantic/pydantic/pull/6516) * Disable E501 from Ruff and rely on just Black by @adriangb in [#6552](https://github.com/pydantic/pydantic/pull/6552) * Update JSON Schema documentation for V2 by @tpdorsey in [#6492](https://github.com/pydantic/pydantic/pull/6492) * Add documentation of cyclic reference handling by @dmontagu in [#6493](https://github.com/pydantic/pydantic/pull/6493) * Remove the need for change files by @samuelcolvin in [#6556](https://github.com/pydantic/pydantic/pull/6556) * add "north star" benchmark by @davidhewitt in [#6547](https://github.com/pydantic/pydantic/pull/6547) * Update Dataclasses docs by @tpdorsey in [#6470](https://github.com/pydantic/pydantic/pull/6470) * ♻️ Use different error message on v1 redirects by @Kludex in [#6595](https://github.com/pydantic/pydantic/pull/6595) * ⬆ Upgrade `pydantic-core` to v2.2.0 by @lig in [#6589](https://github.com/pydantic/pydantic/pull/6589) * Fix serialization for IPvAny by @dmontagu in [#6572](https://github.com/pydantic/pydantic/pull/6572) * Improve CI by using PDM instead of pip to install typing-extensions by @adriangb in [#6602](https://github.com/pydantic/pydantic/pull/6602) * Add `enum` error type docs by @lig in [#6603](https://github.com/pydantic/pydantic/pull/6603) * 🐛 Fix `max_length` for unicode strings by @lig in [#6559](https://github.com/pydantic/pydantic/pull/6559) * Add documentation for accessing features via `pydantic.v1` by @tpdorsey in [#6604](https://github.com/pydantic/pydantic/pull/6604) * Include extra when iterating over a model by @adriangb in [#6562](https://github.com/pydantic/pydantic/pull/6562) * Fix typing of model_validator by @adriangb in [#6514](https://github.com/pydantic/pydantic/pull/6514) * Touch up Decimal validator by @adriangb in [#6327](https://github.com/pydantic/pydantic/pull/6327) * Fix various docstrings using fixed pytest-examples by @dmontagu in [#6607](https://github.com/pydantic/pydantic/pull/6607) * Handle function validators in a discriminated union by @dmontagu in [#6570](https://github.com/pydantic/pydantic/pull/6570) * Review json_schema.md by @tpdorsey in [#6608](https://github.com/pydantic/pydantic/pull/6608) * Make validate_call work on basemodel methods by @dmontagu in [#6569](https://github.com/pydantic/pydantic/pull/6569) * add test for big int json serde by @davidhewitt in [#6614](https://github.com/pydantic/pydantic/pull/6614) * Fix pydantic dataclass problem with dataclasses.field default_factory by @hramezani in [#6616](https://github.com/pydantic/pydantic/pull/6616) * Fixed mypy type inference for TypeAdapter by @zakstucke in [#6617](https://github.com/pydantic/pydantic/pull/6617) * Make it work to use None as a generic parameter by @dmontagu in [#6609](https://github.com/pydantic/pydantic/pull/6609) * Make it work to use `$ref` as an alias by @dmontagu in [#6568](https://github.com/pydantic/pydantic/pull/6568) * add note to migration guide about changes to `AnyUrl` etc by @davidhewitt in [#6618](https://github.com/pydantic/pydantic/pull/6618) * 🐛 Support defining `json_schema_extra` on `RootModel` using `Field` by @lig in [#6622](https://github.com/pydantic/pydantic/pull/6622) * Update pre-commit to prevent commits to main branch on accident by @dmontagu in [#6636](https://github.com/pydantic/pydantic/pull/6636) * Fix PDM CI for python 3.7 on MacOS/windows by @dmontagu in [#6627](https://github.com/pydantic/pydantic/pull/6627) * Produce more accurate signatures for pydantic dataclasses by @dmontagu in [#6633](https://github.com/pydantic/pydantic/pull/6633) * Updates to Url types for Pydantic V2 by @tpdorsey in [#6638](https://github.com/pydantic/pydantic/pull/6638) * Fix list markdown in `transform` docstring by @StefanBRas in [#6649](https://github.com/pydantic/pydantic/pull/6649) * simplify slots_dataclass construction to appease mypy by @davidhewitt in [#6639](https://github.com/pydantic/pydantic/pull/6639) * Update TypedDict schema generation docstring by @adriangb in [#6651](https://github.com/pydantic/pydantic/pull/6651) * Detect and lint-error for prints by @dmontagu in [#6655](https://github.com/pydantic/pydantic/pull/6655) * Add xfailing test for pydantic-core PR 766 by @dmontagu in [#6641](https://github.com/pydantic/pydantic/pull/6641) * Ignore unrecognized fields from dataclasses metadata by @dmontagu in [#6634](https://github.com/pydantic/pydantic/pull/6634) * Make non-existent class getattr a mypy error by @dmontagu in [#6658](https://github.com/pydantic/pydantic/pull/6658) * Update pydantic-core to 2.3.0 by @hramezani in [#6648](https://github.com/pydantic/pydantic/pull/6648) * Use OrderedDict from typing_extensions by @dmontagu in [#6664](https://github.com/pydantic/pydantic/pull/6664) * Fix typehint for JSON schema extra callable by @dmontagu in [#6659](https://github.com/pydantic/pydantic/pull/6659) ## v2.0.2 (2023-07-05) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.0.2) * Fix bug where round-trip pickling/unpickling a `RootModel` would change the value of `__dict__`, [#6457](https://github.com/pydantic/pydantic/pull/6457) by @dmontagu * Allow single-item discriminated unions, [#6405](https://github.com/pydantic/pydantic/pull/6405) by @dmontagu * Fix issue with union parsing of enums, [#6440](https://github.com/pydantic/pydantic/pull/6440) by @dmontagu * Docs: Fixed `constr` documentation, renamed old `regex` to new `pattern`, [#6452](https://github.com/pydantic/pydantic/pull/6452) by @miili * Change `GenerateJsonSchema.generate_definitions` signature, [#6436](https://github.com/pydantic/pydantic/pull/6436) by @dmontagu See the full changelog [here](https://github.com/pydantic/pydantic/releases/tag/v2.0.2) ## v2.0.1 (2023-07-04) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.0.1) First patch release of Pydantic V2 * Extra fields added via `setattr` (i.e. `m.some_extra_field = 'extra_value'`) are added to `.model_extra` if `model_config` `extra='allowed'`. Fixed [#6333](https://github.com/pydantic/pydantic/pull/6333), [#6365](https://github.com/pydantic/pydantic/pull/6365) by @aaraney * Automatically unpack JSON schema '$ref' for custom types, [#6343](https://github.com/pydantic/pydantic/pull/6343) by @adriangb * Fix tagged unions multiple processing in submodels, [#6340](https://github.com/pydantic/pydantic/pull/6340) by @suharnikov See the full changelog [here](https://github.com/pydantic/pydantic/releases/tag/v2.0.1) ## v2.0 (2023-06-30) [GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.0) Pydantic V2 is here! :tada: See [this post](https://docs.pydantic.dev/2.0/blog/pydantic-v2-final/) for more details. ## v2.0b3 (2023-06-16) Third beta pre-release of Pydantic V2 See the full changelog [here](https://github.com/pydantic/pydantic/releases/tag/v2.0b3) ## v2.0b2 (2023-06-03) Add `from_attributes` runtime flag to `TypeAdapter.validate_python` and `BaseModel.model_validate`. See the full changelog [here](https://github.com/pydantic/pydantic/releases/tag/v2.0b2) ## v2.0b1 (2023-06-01) First beta pre-release of Pydantic V2 See the full changelog [here](https://github.com/pydantic/pydantic/releases/tag/v2.0b1) ## v2.0a4 (2023-05-05) Fourth pre-release of Pydantic V2 See the full changelog [here](https://github.com/pydantic/pydantic/releases/tag/v2.0a4) ## v2.0a3 (2023-04-20) Third pre-release of Pydantic V2 See the full changelog [here](https://github.com/pydantic/pydantic/releases/tag/v2.0a3) ## v2.0a2 (2023-04-12) Second pre-release of Pydantic V2 See the full changelog [here](https://github.com/pydantic/pydantic/releases/tag/v2.0a2) ## v2.0a1 (2023-04-03) First pre-release of Pydantic V2! See [this post](https://docs.pydantic.dev/blog/pydantic-v2-alpha/) for more details. ## v1.10.24 (2025-09-25) * Add user warning when using Python 3.14 by @Viicos in https://github.com/pydantic/pydantic/pull/12263 Pydantic V1 will *not* work with Python 3.14 and greater. A warning is now raised as no actual error show up when using it, but the core behavior will silently get broken at runtime. * Fix mypy plugin issue for mypy v1.18 by @cdce8p in https://github.com/pydantic/pydantic/pull/12254 This fixes another mypy issue that was discovered after the previous v1.10.23 release. ## v1.10.23 (2025-09-13) * Fix mypy plugin for mypy 1.18 by @cdce8p in https://github.com/pydantic/pydantic/pull/12207 ## v1.10.22 (2025-04-17) * Fix compatibility with `typing-extensions` by @Viicos in https://github.com/pydantic/pydantic/pull/11764 ## v1.10.21 (2025-01-10) * Fix compatibility with ForwardRef._evaluate and Python < 3.12.4 by @griels in https://github.com/pydantic/pydantic/pull/11232 ## v1.10.20 (2025-01-07) This release provides proper support for Python 3.13, with (Cythonized) wheels published for this version. As a consequence, Cython was updated from `0.29.x` to `3.0.x`. * General maintenance of CI and build ecosystem by @Viicos in https://github.com/pydantic/pydantic/pull/10847 * Update Cython to `3.0.x`. * Properly address Python 3.13 deprecation warnings. * Migrate packaging to `pyproject.toml`, make use of PEP 517 build options. * Use [`build`](https://pypi.org/project/build/) instead of direct `setup.py` invocations. * Update various Github Actions versions. * Replace outdated stpmex link in documentation by @jaredenorris in https://github.com/pydantic/pydantic/pull/10997 ## v1.10.19 (2024-11-06) * Add warning when v2 model is nested in v1 model by @sydney-runkle in https://github.com/pydantic/pydantic/pull/10432 * Fix deprecation warning in V1 `isinstance` check by @alicederyn in https://github.com/pydantic/pydantic/pull/10645 ## v1.10.18 (2024-08-22) * Eval type fix in V1 by @sydney-runkle in https://github.com/pydantic/pydantic/pull/9751 * Add `to_lower_camel` to `__all__` in `utils.py` by @sydney-runkle (direct commit) * Fix `mypy` v1 plugin for mypy 1.11 release by @flaeppe in https://github.com/pydantic/pydantic/pull/10139 * Fix discriminator key used when discriminator has alias and `.schema(by_alias=False)` by @exs-dwoodward in https://github.com/pydantic/pydantic/pull/10146 ## v1.10.17 (2024-06-20) * Advertise Python 3.12 for 1.10.x! Part Deux by @vfazio in https://github.com/pydantic/pydantic/pull/9644 * Mirrored modules in `v1` namespace to fix typing and object resolution in python>3.11 by @exs-dwoodward in https://github.com/pydantic/pydantic/pull/9660 * setup: remove upper bound from python_requires by @vfazio in https://github.com/pydantic/pydantic/pull/9685 ## v1.10.16 (2024-06-11) * Specify recursive_guard as kwarg in FutureRef._evaluate by @vfazio in https://github.com/pydantic/pydantic/pull/9612 * Fix mypy v1 plugin for upcoming mypy release by @ cdce8p in https://github.com/pydantic/pydantic/pull/9586 * Import modules/objects directly from v1 namespace by @exs-dwoodward in https://github.com/pydantic/pydantic/pull/9162 ## v1.10.15 (2024-04-03) * Add pydantic.v1 namespace to Pydantic v1 by @exs-dmiketa in https://github.com/pydantic/pydantic/pull/9042 * Relax version of typing-extensions for V1 by @SonOfLilit in https://github.com/pydantic/pydantic/pull/8819 * patch fix for mypy by @sydney-runkle in https://github.com/pydantic/pydantic/pull/8765 ## v1.10.14 (2024-01-19) * Update install.md by @dmontagu in #7690 * Fix ci to only deploy docs on release by @sydney-runkle in #7740 * Ubuntu fixes for V1 by @sydney-runkle in #8540 and #8587 * Fix cached_property handling in dataclasses when copied by @rdbisme in #8407 ## v1.10.13 (2023-09-27) * Fix: Add max length check to `pydantic.validate_email`, #7673 by @hramezani * Docs: Fix pip commands to install v1, #6930 by @chbndrhnns ## v1.10.12 (2023-07-24) * Fixes the `maxlen` property being dropped on `deque` validation. Happened only if the deque item has been typed. Changes the `_validate_sequence_like` func, [#6581](https://github.com/pydantic/pydantic/pull/6581) by @maciekglowka ## v1.10.11 (2023-07-04) * Importing create_model in tools.py through relative path instead of absolute path - so that it doesn't import V2 code when copied over to V2 branch, [#6361](https://github.com/pydantic/pydantic/pull/6361) by @SharathHuddar ## v1.10.10 (2023-06-30) * Add Pydantic `Json` field support to settings management, [#6250](https://github.com/pydantic/pydantic/pull/6250) by @hramezani * Fixed literal validator errors for unhashable values, [#6188](https://github.com/pydantic/pydantic/pull/6188) by @markus1978 * Fixed bug with generics receiving forward refs, [#6130](https://github.com/pydantic/pydantic/pull/6130) by @mark-todd * Update install method of FastAPI for internal tests in CI, [#6117](https://github.com/pydantic/pydantic/pull/6117) by @Kludex ## v1.10.9 (2023-06-07) * Fix trailing zeros not ignored in Decimal validation, [#5968](https://github.com/pydantic/pydantic/pull/5968) by @hramezani * Fix mypy plugin for v1.4.0, [#5928](https://github.com/pydantic/pydantic/pull/5928) by @cdce8p * Add future and past date hypothesis strategies, [#5850](https://github.com/pydantic/pydantic/pull/5850) by @bschoenmaeckers * Discourage usage of Cython 3 with Pydantic 1.x, [#5845](https://github.com/pydantic/pydantic/pull/5845) by @lig ## v1.10.8 (2023-05-23) * Fix a bug in `Literal` usage with `typing-extension==4.6.0`, [#5826](https://github.com/pydantic/pydantic/pull/5826) by @hramezani * This solves the (closed) issue [#3849](https://github.com/pydantic/pydantic/pull/3849) where aliased fields that use discriminated union fail to validate when the data contains the non-aliased field name, [#5736](https://github.com/pydantic/pydantic/pull/5736) by @benwah * Update email-validator dependency to >=2.0.0post2, [#5627](https://github.com/pydantic/pydantic/pull/5627) by @adriangb * update `AnyClassMethod` for changes in [python/typeshed#9771](https://github.com/python/typeshed/issues/9771), [#5505](https://github.com/pydantic/pydantic/pull/5505) by @ITProKyle ## v1.10.7 (2023-03-22) * Fix creating schema from model using `ConstrainedStr` with `regex` as dict key, [#5223](https://github.com/pydantic/pydantic/pull/5223) by @matejetz * Address bug in mypy plugin caused by explicit_package_bases=True, [#5191](https://github.com/pydantic/pydantic/pull/5191) by @dmontagu * Add implicit defaults in the mypy plugin for Field with no default argument, [#5190](https://github.com/pydantic/pydantic/pull/5190) by @dmontagu * Fix schema generated for Enum values used as Literals in discriminated unions, [#5188](https://github.com/pydantic/pydantic/pull/5188) by @javibookline * Fix mypy failures caused by the pydantic mypy plugin when users define `from_orm` in their own classes, [#5187](https://github.com/pydantic/pydantic/pull/5187) by @dmontagu * Fix `InitVar` usage with pydantic dataclasses, mypy version `1.1.1` and the custom mypy plugin, [#5162](https://github.com/pydantic/pydantic/pull/5162) by @cdce8p ## v1.10.6 (2023-03-08) * Implement logic to support creating validators from non standard callables by using defaults to identify them and unwrapping `functools.partial` and `functools.partialmethod` when checking the signature, [#5126](https://github.com/pydantic/pydantic/pull/5126) by @JensHeinrich * Fix mypy plugin for v1.1.1, and fix `dataclass_transform` decorator for pydantic dataclasses, [#5111](https://github.com/pydantic/pydantic/pull/5111) by @cdce8p * Raise `ValidationError`, not `ConfigError`, when a discriminator value is unhashable, [#4773](https://github.com/pydantic/pydantic/pull/4773) by @kurtmckee ## v1.10.5 (2023-02-15) * Fix broken parametrized bases handling with `GenericModel`s with complex sets of models, [#5052](https://github.com/pydantic/pydantic/pull/5052) by @MarkusSintonen * Invalidate mypy cache if plugin config changes, [#5007](https://github.com/pydantic/pydantic/pull/5007) by @cdce8p * Fix `RecursionError` when deep-copying dataclass types wrapped by pydantic, [#4949](https://github.com/pydantic/pydantic/pull/4949) by @mbillingr * Fix `X | Y` union syntax breaking `GenericModel`, [#4146](https://github.com/pydantic/pydantic/pull/4146) by @thenx * Switch coverage badge to show coverage for this branch/release, [#5060](https://github.com/pydantic/pydantic/pull/5060) by @samuelcolvin ## v1.10.4 (2022-12-30) * Change dependency to `typing-extensions>=4.2.0`, [#4885](https://github.com/pydantic/pydantic/pull/4885) by @samuelcolvin ## v1.10.3 (2022-12-29) **NOTE: v1.10.3 was ["yanked"](https://pypi.org/help/#yanked) from PyPI due to [#4885](https://github.com/pydantic/pydantic/pull/4885) which is fixed in v1.10.4** * fix parsing of custom root models, [#4883](https://github.com/pydantic/pydantic/pull/4883) by @gou177 * fix: use dataclass proxy for frozen or empty dataclasses, [#4878](https://github.com/pydantic/pydantic/pull/4878) by @PrettyWood * Fix `schema` and `schema_json` on models where a model instance is a one of default values, [#4781](https://github.com/pydantic/pydantic/pull/4781) by @Bobronium * Add Jina AI to sponsors on docs index page, [#4767](https://github.com/pydantic/pydantic/pull/4767) by @samuelcolvin * fix: support assignment on `DataclassProxy`, [#4695](https://github.com/pydantic/pydantic/pull/4695) by @PrettyWood * Add `postgresql+psycopg` as allowed scheme for `PostgreDsn` to make it usable with SQLAlchemy 2, [#4689](https://github.com/pydantic/pydantic/pull/4689) by @morian * Allow dict schemas to have both `patternProperties` and `additionalProperties`, [#4641](https://github.com/pydantic/pydantic/pull/4641) by @jparise * Fixes error passing None for optional lists with `unique_items`, [#4568](https://github.com/pydantic/pydantic/pull/4568) by @mfulgo * Fix `GenericModel` with `Callable` param raising a `TypeError`, [#4551](https://github.com/pydantic/pydantic/pull/4551) by @mfulgo * Fix field regex with `StrictStr` type annotation, [#4538](https://github.com/pydantic/pydantic/pull/4538) by @sisp * Correct `dataclass_transform` keyword argument name from `field_descriptors` to `field_specifiers`, [#4500](https://github.com/pydantic/pydantic/pull/4500) by @samuelcolvin * fix: avoid multiple calls of `__post_init__` when dataclasses are inherited, [#4487](https://github.com/pydantic/pydantic/pull/4487) by @PrettyWood * Reduce the size of binary wheels, [#2276](https://github.com/pydantic/pydantic/pull/2276) by @samuelcolvin ## v1.10.2 (2022-09-05) * **Revert Change:** Revert percent encoding of URL parts which was originally added in [#4224](https://github.com/pydantic/pydantic/pull/4224), [#4470](https://github.com/pydantic/pydantic/pull/4470) by @samuelcolvin * Prevent long (length > `4_300`) strings/bytes as input to int fields, see [python/cpython#95778](https://github.com/python/cpython/issues/95778) and [CVE-2020-10735](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-10735), [#1477](https://github.com/pydantic/pydantic/pull/1477) by @samuelcolvin * fix: dataclass wrapper was not always called, [#4477](https://github.com/pydantic/pydantic/pull/4477) by @PrettyWood * Use `tomllib` on Python 3.11 when parsing `mypy` configuration, [#4476](https://github.com/pydantic/pydantic/pull/4476) by @hauntsaninja * Basic fix of `GenericModel` cache to detect order of arguments in `Union` models, [#4474](https://github.com/pydantic/pydantic/pull/4474) by @sveinugu * Fix mypy plugin when using bare types like `list` and `dict` as `default_factory`, [#4457](https://github.com/pydantic/pydantic/pull/4457) by @samuelcolvin ## v1.10.1 (2022-08-31) * Add `__hash__` method to `pydantic.color.Color` class, [#4454](https://github.com/pydantic/pydantic/pull/4454) by @czaki ## v1.10.0 (2022-08-30) * Refactor the whole *pydantic* `dataclass` decorator to really act like its standard lib equivalent. It hence keeps `__eq__`, `__hash__`, ... and makes comparison with its non-validated version possible. It also fixes usage of `frozen` dataclasses in fields and usage of `default_factory` in nested dataclasses. The support of `Config.extra` has been added. Finally, config customization directly via a `dict` is now possible, [#2557](https://github.com/pydantic/pydantic/pull/2557) by @PrettyWood

**BREAKING CHANGES:** * The `compiled` boolean (whether *pydantic* is compiled with cython) has been moved from `main.py` to `version.py` * Now that `Config.extra` is supported, `dataclass` ignores by default extra arguments (like `BaseModel`) * Fix PEP487 `__set_name__` protocol in `BaseModel` for PrivateAttrs, [#4407](https://github.com/pydantic/pydantic/pull/4407) by @tlambert03 * Allow for custom parsing of environment variables via `parse_env_var` in `Config`, [#4406](https://github.com/pydantic/pydantic/pull/4406) by @acmiyaguchi * Rename `master` to `main`, [#4405](https://github.com/pydantic/pydantic/pull/4405) by @hramezani * Fix `StrictStr` does not raise `ValidationError` when `max_length` is present in `Field`, [#4388](https://github.com/pydantic/pydantic/pull/4388) by @hramezani * Make `SecretStr` and `SecretBytes` hashable, [#4387](https://github.com/pydantic/pydantic/pull/4387) by @chbndrhnns * Fix `StrictBytes` does not raise `ValidationError` when `max_length` is present in `Field`, [#4380](https://github.com/pydantic/pydantic/pull/4380) by @JeanArhancet * Add support for bare `type`, [#4375](https://github.com/pydantic/pydantic/pull/4375) by @hramezani * Support Python 3.11, including binaries for 3.11 in PyPI, [#4374](https://github.com/pydantic/pydantic/pull/4374) by @samuelcolvin * Add support for `re.Pattern`, [#4366](https://github.com/pydantic/pydantic/pull/4366) by @hramezani * Fix `__post_init_post_parse__` is incorrectly passed keyword arguments when no `__post_init__` is defined, [#4361](https://github.com/pydantic/pydantic/pull/4361) by @hramezani * Fix implicitly importing `ForwardRef` and `Callable` from `pydantic.typing` instead of `typing` and also expose `MappingIntStrAny`, [#4358](https://github.com/pydantic/pydantic/pull/4358) by @aminalaee * remove `Any` types from the `dataclass` decorator so it can be used with the `disallow_any_expr` mypy option, [#4356](https://github.com/pydantic/pydantic/pull/4356) by @DetachHead * moved repo to `pydantic/pydantic`, [#4348](https://github.com/pydantic/pydantic/pull/4348) by @yezz123 * fix "extra fields not permitted" error when dataclass with `Extra.forbid` is validated multiple times, [#4343](https://github.com/pydantic/pydantic/pull/4343) by @detachhead * Add Python 3.9 and 3.10 examples to docs, [#4339](https://github.com/pydantic/pydantic/pull/4339) by @Bobronium * Discriminated union models now use `oneOf` instead of `anyOf` when generating OpenAPI schema definitions, [#4335](https://github.com/pydantic/pydantic/pull/4335) by @MaxwellPayne * Allow type checkers to infer inner type of `Json` type. `Json[list[str]]` will be now inferred as `list[str]`, `Json[Any]` should be used instead of plain `Json`. Runtime behaviour is not changed, [#4332](https://github.com/pydantic/pydantic/pull/4332) by @Bobronium * Allow empty string aliases by using a `alias is not None` check, rather than `bool(alias)`, [#4253](https://github.com/pydantic/pydantic/pull/4253) by @sergeytsaplin * Update `ForwardRef`s in `Field.outer_type_`, [#4249](https://github.com/pydantic/pydantic/pull/4249) by @JacobHayes * The use of `__dataclass_transform__` has been replaced by `typing_extensions.dataclass_transform`, which is the preferred way to mark pydantic models as a dataclass under [PEP 681](https://peps.python.org/pep-0681/), [#4241](https://github.com/pydantic/pydantic/pull/4241) by @multimeric * Use parent model's `Config` when validating nested `NamedTuple` fields, [#4219](https://github.com/pydantic/pydantic/pull/4219) by @synek * Update `BaseModel.construct` to work with aliased Fields, [#4192](https://github.com/pydantic/pydantic/pull/4192) by @kylebamos * Catch certain raised errors in `smart_deepcopy` and revert to `deepcopy` if so, [#4184](https://github.com/pydantic/pydantic/pull/4184) by @coneybeare * Add `Config.anystr_upper` and `to_upper` kwarg to constr and conbytes, [#4165](https://github.com/pydantic/pydantic/pull/4165) by @satheler * Fix JSON schema for `set` and `frozenset` when they include default values, [#4155](https://github.com/pydantic/pydantic/pull/4155) by @aminalaee * Teach the mypy plugin that methods decorated by `@validator` are classmethods, [#4102](https://github.com/pydantic/pydantic/pull/4102) by @DMRobertson * Improve mypy plugin's ability to detect required fields, [#4086](https://github.com/pydantic/pydantic/pull/4086) by @richardxia * Support fields of type `Type[]` in schema, [#4051](https://github.com/pydantic/pydantic/pull/4051) by @aminalaee * Add `default` value in JSON Schema when `const=True`, [#4031](https://github.com/pydantic/pydantic/pull/4031) by @aminalaee * Adds reserved word check to signature generation logic, [#4011](https://github.com/pydantic/pydantic/pull/4011) by @strue36 * Fix Json strategy failure for the complex nested field, [#4005](https://github.com/pydantic/pydantic/pull/4005) by @sergiosim * Add JSON-compatible float constraint `allow_inf_nan`, [#3994](https://github.com/pydantic/pydantic/pull/3994) by @tiangolo * Remove undefined behaviour when `env_prefix` had characters in common with `env_nested_delimiter`, [#3975](https://github.com/pydantic/pydantic/pull/3975) by @arsenron * Support generics model with `create_model`, [#3945](https://github.com/pydantic/pydantic/pull/3945) by @hot123s * allow submodels to overwrite extra field info, [#3934](https://github.com/pydantic/pydantic/pull/3934) by @PrettyWood * Document and test structural pattern matching ([PEP 636](https://peps.python.org/pep-0636/)) on `BaseModel`, [#3920](https://github.com/pydantic/pydantic/pull/3920) by @irgolic * Fix incorrect deserialization of python timedelta object to ISO 8601 for negative time deltas. Minus was serialized in incorrect place ("P-1DT23H59M59.888735S" instead of correct "-P1DT23H59M59.888735S"), [#3899](https://github.com/pydantic/pydantic/pull/3899) by @07pepa * Fix validation of discriminated union fields with an alias when passing a model instance, [#3846](https://github.com/pydantic/pydantic/pull/3846) by @chornsby * Add a CockroachDsn type to validate CockroachDB connection strings. The type supports the following schemes: `cockroachdb`, `cockroachdb+psycopg2` and `cockroachdb+asyncpg`, [#3839](https://github.com/pydantic/pydantic/pull/3839) by @blubber * Fix MyPy plugin to not override pre-existing `__init__` method in models, [#3824](https://github.com/pydantic/pydantic/pull/3824) by @patrick91 * Fix mypy version checking, [#3783](https://github.com/pydantic/pydantic/pull/3783) by @KotlinIsland * support overwriting dunder attributes of `BaseModel` instances, [#3777](https://github.com/pydantic/pydantic/pull/3777) by @PrettyWood * Added `ConstrainedDate` and `condate`, [#3740](https://github.com/pydantic/pydantic/pull/3740) by @hottwaj * Support `kw_only` in dataclasses, [#3670](https://github.com/pydantic/pydantic/pull/3670) by @detachhead * Add comparison method for `Color` class, [#3646](https://github.com/pydantic/pydantic/pull/3646) by @aminalaee * Drop support for python3.6, associated cleanup, [#3605](https://github.com/pydantic/pydantic/pull/3605) by @samuelcolvin * created new function `to_lower_camel()` for "non pascal case" camel case, [#3463](https://github.com/pydantic/pydantic/pull/3463) by @schlerp * Add checks to `default` and `default_factory` arguments in Mypy plugin, [#3430](https://github.com/pydantic/pydantic/pull/3430) by @klaa97 * fix mangling of `inspect.signature` for `BaseModel`, [#3413](https://github.com/pydantic/pydantic/pull/3413) by @fix-inspect-signature * Adds the `SecretField` abstract class so that all the current and future secret fields like `SecretStr` and `SecretBytes` will derive from it, [#3409](https://github.com/pydantic/pydantic/pull/3409) by @expobrain * Support multi hosts validation in `PostgresDsn`, [#3337](https://github.com/pydantic/pydantic/pull/3337) by @rglsk * Fix parsing of very small numeric timedelta values, [#3315](https://github.com/pydantic/pydantic/pull/3315) by @samuelcolvin * Update `SecretsSettingsSource` to respect `config.case_sensitive`, [#3273](https://github.com/pydantic/pydantic/pull/3273) by @JeanArhancet * Add MongoDB network data source name (DSN) schema, [#3229](https://github.com/pydantic/pydantic/pull/3229) by @snosratiershad * Add support for multiple dotenv files, [#3222](https://github.com/pydantic/pydantic/pull/3222) by @rekyungmin * Raise an explicit `ConfigError` when multiple fields are incorrectly set for a single validator, [#3215](https://github.com/pydantic/pydantic/pull/3215) by @SunsetOrange * Allow ellipsis on `Field`s inside `Annotated` for `TypedDicts` required, [#3133](https://github.com/pydantic/pydantic/pull/3133) by @ezegomez * Catch overflow errors in `int_validator`, [#3112](https://github.com/pydantic/pydantic/pull/3112) by @ojii * Adds a `__rich_repr__` method to `Representation` class which enables pretty printing with [Rich](https://github.com/willmcgugan/rich), [#3099](https://github.com/pydantic/pydantic/pull/3099) by @willmcgugan * Add percent encoding in `AnyUrl` and descendent types, [#3061](https://github.com/pydantic/pydantic/pull/3061) by @FaresAhmedb * `validate_arguments` decorator now supports `alias`, [#3019](https://github.com/pydantic/pydantic/pull/3019) by @MAD-py * Avoid `__dict__` and `__weakref__` attributes in `AnyUrl` and IP address fields, [#2890](https://github.com/pydantic/pydantic/pull/2890) by @nuno-andre * Add ability to use `Final` in a field type annotation, [#2766](https://github.com/pydantic/pydantic/pull/2766) by @uriyyo * Update requirement to `typing_extensions>=4.1.0` to guarantee `dataclass_transform` is available, [#4424](https://github.com/pydantic/pydantic/pull/4424) by @commonism * Add Explosion and AWS to main sponsors, [#4413](https://github.com/pydantic/pydantic/pull/4413) by @samuelcolvin * Update documentation for `copy_on_model_validation` to reflect recent changes, [#4369](https://github.com/pydantic/pydantic/pull/4369) by @samuelcolvin * Runtime warning if `__slots__` is passed to `create_model`, `__slots__` is then ignored, [#4432](https://github.com/pydantic/pydantic/pull/4432) by @samuelcolvin * Add type hints to `BaseSettings.Config` to avoid mypy errors, also correct mypy version compatibility notice in docs, [#4450](https://github.com/pydantic/pydantic/pull/4450) by @samuelcolvin ## v1.10.0b1 (2022-08-24) Pre-release, see [the GitHub release](https://github.com/pydantic/pydantic/releases/tag/v1.10.0b1) for details. ## v1.10.0a2 (2022-08-24) Pre-release, see [the GitHub release](https://github.com/pydantic/pydantic/releases/tag/v1.10.0a2) for details. ## v1.10.0a1 (2022-08-22) Pre-release, see [the GitHub release](https://github.com/pydantic/pydantic/releases/tag/v1.10.0a1) for details. ## v1.9.2 (2022-08-11) **Revert Breaking Change**: *v1.9.1* introduced a breaking change where model fields were deep copied by default, this release reverts the default behaviour to match *v1.9.0* and before, while also allow deep-copy behaviour via `copy_on_model_validation = 'deep'`. See [#4092](https://github.com/pydantic/pydantic/pull/4092) for more information. * Allow for shallow copies of model fields, `Config.copy_on_model_validation` is now a str which must be `'none'`, `'deep'`, or `'shallow'` corresponding to not copying, deep copy & shallow copy; default `'shallow'`, [#4093](https://github.com/pydantic/pydantic/pull/4093) by @timkpaine ## v1.9.1 (2022-05-19) Thank you to pydantic's sponsors: @tiangolo, @stellargraph, @JonasKs, @grillazz, @Mazyod, @kevinalh, @chdsbd, @povilasb, @povilasb, @jina-ai, @mainframeindustries, @robusta-dev, @SendCloud, @rszamszur, @jodal, @hardbyte, @corleyma, @daddycocoaman, @Rehket, @jokull, @reillysiemens, @westonsteimel, @primer-io, @koxudaxi, @browniebroke, @stradivari96, @adriangb, @kamalgill, @jqueguiner, @dev-zero, @datarootsio, @RedCarpetUp for their kind support. * Limit the size of `generics._generic_types_cache` and `generics._assigned_parameters` to avoid unlimited increase in memory usage, [#4083](https://github.com/pydantic/pydantic/pull/4083) by @samuelcolvin * Add Jupyverse and FPS as Jupyter projects using pydantic, [#4082](https://github.com/pydantic/pydantic/pull/4082) by @davidbrochart * Speedup `__isinstancecheck__` on pydantic models when the type is not a model, may also avoid memory "leaks", [#4081](https://github.com/pydantic/pydantic/pull/4081) by @samuelcolvin * Fix in-place modification of `FieldInfo` that caused problems with PEP 593 type aliases, [#4067](https://github.com/pydantic/pydantic/pull/4067) by @adriangb * Add support for autocomplete in VS Code via `__dataclass_transform__` when using `pydantic.dataclasses.dataclass`, [#4006](https://github.com/pydantic/pydantic/pull/4006) by @giuliano-oliveira * Remove benchmarks from codebase and docs, [#3973](https://github.com/pydantic/pydantic/pull/3973) by @samuelcolvin * Typing checking with pyright in CI, improve docs on vscode/pylance/pyright, [#3972](https://github.com/pydantic/pydantic/pull/3972) by @samuelcolvin * Fix nested Python dataclass schema regression, [#3819](https://github.com/pydantic/pydantic/pull/3819) by @himbeles * Update documentation about lazy evaluation of sources for Settings, [#3806](https://github.com/pydantic/pydantic/pull/3806) by @garyd203 * Prevent subclasses of bytes being converted to bytes, [#3706](https://github.com/pydantic/pydantic/pull/3706) by @samuelcolvin * Fixed "error checking inheritance of" when using PEP585 and PEP604 type hints, [#3681](https://github.com/pydantic/pydantic/pull/3681) by @aleksul * Allow self referencing `ClassVar`s in models, [#3679](https://github.com/pydantic/pydantic/pull/3679) by @samuelcolvin * **Breaking Change, see [#4106](https://github.com/pydantic/pydantic/pull/4106)**: Fix issue with self-referencing dataclass, [#3675](https://github.com/pydantic/pydantic/pull/3675) by @uriyyo * Include non-standard port numbers in rendered URLs, [#3652](https://github.com/pydantic/pydantic/pull/3652) by @dolfinus * `Config.copy_on_model_validation` does a deep copy and not a shallow one, [#3641](https://github.com/pydantic/pydantic/pull/3641) by @PrettyWood * fix: clarify that discriminated unions do not support singletons, [#3636](https://github.com/pydantic/pydantic/pull/3636) by @tommilligan * Add `read_text(encoding='utf-8')` for `setup.py`, [#3625](https://github.com/pydantic/pydantic/pull/3625) by @hswong3i * Fix JSON Schema generation for Discriminated Unions within lists, [#3608](https://github.com/pydantic/pydantic/pull/3608) by @samuelcolvin ## v1.9.0 (2021-12-31) Thank you to pydantic's sponsors: @sthagen, @timdrijvers, @toinbis, @koxudaxi, @ginomempin, @primer-io, @and-semakin, @westonsteimel, @reillysiemens, @es3n1n, @jokull, @JonasKs, @Rehket, @corleyma, @daddycocoaman, @hardbyte, @datarootsio, @jodal, @aminalaee, @rafsaf, @jqueguiner, @chdsbd, @kevinalh, @Mazyod, @grillazz, @JonasKs, @simw, @leynier, @xfenix for their kind support. ### Highlights * add Python 3.10 support, [#2885](https://github.com/pydantic/pydantic/pull/2885) by @PrettyWood * [Discriminated unions](https://docs.pydantic.dev/usage/types/#discriminated-unions-aka-tagged-unions), [#619](https://github.com/pydantic/pydantic/pull/619) by @PrettyWood * [`Config.smart_union` for better union logic](https://docs.pydantic.dev/usage/model_config/#smart-union), [#2092](https://github.com/pydantic/pydantic/pull/2092) by @PrettyWood * Binaries for Macos M1 CPUs, [#3498](https://github.com/pydantic/pydantic/pull/3498) by @samuelcolvin * Complex types can be set via [nested environment variables](https://docs.pydantic.dev/usage/settings/#parsing-environment-variable-values), e.g. `foo___bar`, [#3159](https://github.com/pydantic/pydantic/pull/3159) by @Air-Mark * add a dark mode to *pydantic* documentation, [#2913](https://github.com/pydantic/pydantic/pull/2913) by @gbdlin * Add support for autocomplete in VS Code via `__dataclass_transform__`, [#2721](https://github.com/pydantic/pydantic/pull/2721) by @tiangolo * Add "exclude" as a field parameter so that it can be configured using model config, [#660](https://github.com/pydantic/pydantic/pull/660) by @daviskirk ### v1.9.0 (2021-12-31) Changes * Apply `update_forward_refs` to `Config.json_encodes` prevent name clashes in types defined via strings, [#3583](https://github.com/pydantic/pydantic/pull/3583) by @samuelcolvin * Extend pydantic's mypy plugin to support mypy versions `0.910`, `0.920`, `0.921` & `0.930`, [#3573](https://github.com/pydantic/pydantic/pull/3573) & [#3594](https://github.com/pydantic/pydantic/pull/3594) by @PrettyWood, @christianbundy, @samuelcolvin ### v1.9.0a2 (2021-12-24) Changes * support generic models with discriminated union, [#3551](https://github.com/pydantic/pydantic/pull/3551) by @PrettyWood * keep old behaviour of `json()` by default, [#3542](https://github.com/pydantic/pydantic/pull/3542) by @PrettyWood * Removed typing-only `__root__` attribute from `BaseModel`, [#3540](https://github.com/pydantic/pydantic/pull/3540) by @layday * Build Python 3.10 wheels, [#3539](https://github.com/pydantic/pydantic/pull/3539) by @mbachry * Fix display of `extra` fields with model `__repr__`, [#3234](https://github.com/pydantic/pydantic/pull/3234) by @cocolman * models copied via `Config.copy_on_model_validation` always have all fields, [#3201](https://github.com/pydantic/pydantic/pull/3201) by @PrettyWood * nested ORM from nested dictionaries, [#3182](https://github.com/pydantic/pydantic/pull/3182) by @PrettyWood * fix link to discriminated union section by @PrettyWood ### v1.9.0a1 (2021-12-18) Changes * Add support for `Decimal`-specific validation configurations in `Field()`, additionally to using `condecimal()`, to allow better support from editors and tooling, [#3507](https://github.com/pydantic/pydantic/pull/3507) by @tiangolo * Add `arm64` binaries suitable for MacOS with an M1 CPU to PyPI, [#3498](https://github.com/pydantic/pydantic/pull/3498) by @samuelcolvin * Fix issue where `None` was considered invalid when using a `Union` type containing `Any` or `object`, [#3444](https://github.com/pydantic/pydantic/pull/3444) by @tharradine * When generating field schema, pass optional `field` argument (of type `pydantic.fields.ModelField`) to `__modify_schema__()` if present, [#3434](https://github.com/pydantic/pydantic/pull/3434) by @jasujm * Fix issue when pydantic fail to parse `typing.ClassVar` string type annotation, [#3401](https://github.com/pydantic/pydantic/pull/3401) by @uriyyo * Mention Python >= 3.9.2 as an alternative to `typing_extensions.TypedDict`, [#3374](https://github.com/pydantic/pydantic/pull/3374) by @BvB93 * Changed the validator method name in the [Custom Errors example](https://docs.pydantic.dev/usage/models/#custom-errors) to more accurately describe what the validator is doing; changed from `name_must_contain_space` to `value_must_equal_bar`, [#3327](https://github.com/pydantic/pydantic/pull/3327) by @michaelrios28 * Add `AmqpDsn` class, [#3254](https://github.com/pydantic/pydantic/pull/3254) by @kludex * Always use `Enum` value as default in generated JSON schema, [#3190](https://github.com/pydantic/pydantic/pull/3190) by @joaommartins * Add support for Mypy 0.920, [#3175](https://github.com/pydantic/pydantic/pull/3175) by @christianbundy * `validate_arguments` now supports `extra` customization (used to always be `Extra.forbid`), [#3161](https://github.com/pydantic/pydantic/pull/3161) by @PrettyWood * Complex types can be set by nested environment variables, [#3159](https://github.com/pydantic/pydantic/pull/3159) by @Air-Mark * Fix mypy plugin to collect fields based on `pydantic.utils.is_valid_field` so that it ignores untyped private variables, [#3146](https://github.com/pydantic/pydantic/pull/3146) by @hi-ogawa * fix `validate_arguments` issue with `Config.validate_all`, [#3135](https://github.com/pydantic/pydantic/pull/3135) by @PrettyWood * avoid dict coercion when using dict subclasses as field type, [#3122](https://github.com/pydantic/pydantic/pull/3122) by @PrettyWood * add support for `object` type, [#3062](https://github.com/pydantic/pydantic/pull/3062) by @PrettyWood * Updates pydantic dataclasses to keep `_special` properties on parent classes, [#3043](https://github.com/pydantic/pydantic/pull/3043) by @zulrang * Add a `TypedDict` class for error objects, [#3038](https://github.com/pydantic/pydantic/pull/3038) by @matthewhughes934 * Fix support for using a subclass of an annotation as a default, [#3018](https://github.com/pydantic/pydantic/pull/3018) by @JacobHayes * make `create_model_from_typeddict` mypy compliant, [#3008](https://github.com/pydantic/pydantic/pull/3008) by @PrettyWood * Make multiple inheritance work when using `PrivateAttr`, [#2989](https://github.com/pydantic/pydantic/pull/2989) by @hmvp * Parse environment variables as JSON, if they have a `Union` type with a complex subfield, [#2936](https://github.com/pydantic/pydantic/pull/2936) by @cbartz * Prevent `StrictStr` permitting `Enum` values where the enum inherits from `str`, [#2929](https://github.com/pydantic/pydantic/pull/2929) by @samuelcolvin * Make `SecretsSettingsSource` parse values being assigned to fields of complex types when sourced from a secrets file, just as when sourced from environment variables, [#2917](https://github.com/pydantic/pydantic/pull/2917) by @davidmreed * add a dark mode to *pydantic* documentation, [#2913](https://github.com/pydantic/pydantic/pull/2913) by @gbdlin * Make `pydantic-mypy` plugin compatible with `pyproject.toml` configuration, consistent with `mypy` changes. See the [doc](https://docs.pydantic.dev/mypy_plugin/#configuring-the-plugin) for more information, [#2908](https://github.com/pydantic/pydantic/pull/2908) by @jrwalk * add Python 3.10 support, [#2885](https://github.com/pydantic/pydantic/pull/2885) by @PrettyWood * Correctly parse generic models with `Json[T]`, [#2860](https://github.com/pydantic/pydantic/pull/2860) by @geekingfrog * Update contrib docs re: Python version to use for building docs, [#2856](https://github.com/pydantic/pydantic/pull/2856) by @paxcodes * Clarify documentation about *pydantic*'s support for custom validation and strict type checking, despite *pydantic* being primarily a parsing library, [#2855](https://github.com/pydantic/pydantic/pull/2855) by @paxcodes * Fix schema generation for `Deque` fields, [#2810](https://github.com/pydantic/pydantic/pull/2810) by @sergejkozin * fix an edge case when mixing constraints and `Literal`, [#2794](https://github.com/pydantic/pydantic/pull/2794) by @PrettyWood * Fix postponed annotation resolution for `NamedTuple` and `TypedDict` when they're used directly as the type of fields within Pydantic models, [#2760](https://github.com/pydantic/pydantic/pull/2760) by @jameysharp * Fix bug when `mypy` plugin fails on `construct` method call for `BaseSettings` derived classes, [#2753](https://github.com/pydantic/pydantic/pull/2753) by @uriyyo * Add function overloading for a `pydantic.create_model` function, [#2748](https://github.com/pydantic/pydantic/pull/2748) by @uriyyo * Fix mypy plugin issue with self field declaration, [#2743](https://github.com/pydantic/pydantic/pull/2743) by @uriyyo * The colon at the end of the line "The fields which were supplied when user was initialised:" suggests that the code following it is related. Changed it to a period, [#2733](https://github.com/pydantic/pydantic/pull/2733) by @krisaoe * Renamed variable `schema` to `schema_` to avoid shadowing of global variable name, [#2724](https://github.com/pydantic/pydantic/pull/2724) by @shahriyarr * Add support for autocomplete in VS Code via `__dataclass_transform__`, [#2721](https://github.com/pydantic/pydantic/pull/2721) by @tiangolo * add missing type annotations in `BaseConfig` and handle `max_length = 0`, [#2719](https://github.com/pydantic/pydantic/pull/2719) by @PrettyWood * Change `orm_mode` checking to allow recursive ORM mode parsing with dicts, [#2718](https://github.com/pydantic/pydantic/pull/2718) by @nuno-andre * Add episode 313 of the *Talk Python To Me* podcast, where Michael Kennedy and Samuel Colvin discuss Pydantic, to the docs, [#2712](https://github.com/pydantic/pydantic/pull/2712) by @RatulMaharaj * fix JSON schema generation when a field is of type `NamedTuple` and has a default value, [#2707](https://github.com/pydantic/pydantic/pull/2707) by @PrettyWood * `Enum` fields now properly support extra kwargs in schema generation, [#2697](https://github.com/pydantic/pydantic/pull/2697) by @sammchardy * **Breaking Change, see [#3780](https://github.com/pydantic/pydantic/pull/3780)**: Make serialization of referenced pydantic models possible, [#2650](https://github.com/pydantic/pydantic/pull/2650) by @PrettyWood * Add `uniqueItems` option to `ConstrainedList`, [#2618](https://github.com/pydantic/pydantic/pull/2618) by @nuno-andre * Try to evaluate forward refs automatically at model creation, [#2588](https://github.com/pydantic/pydantic/pull/2588) by @uriyyo * Switch docs preview and coverage display to use [smokeshow](https://smokeshow.helpmanual.io/), [#2580](https://github.com/pydantic/pydantic/pull/2580) by @samuelcolvin * Add `__version__` attribute to pydantic module, [#2572](https://github.com/pydantic/pydantic/pull/2572) by @paxcodes * Add `postgresql+asyncpg`, `postgresql+pg8000`, `postgresql+psycopg2`, `postgresql+psycopg2cffi`, `postgresql+py-postgresql` and `postgresql+pygresql` schemes for `PostgresDsn`, [#2567](https://github.com/pydantic/pydantic/pull/2567) by @postgres-asyncpg * Enable the Hypothesis plugin to generate a constrained decimal when the `decimal_places` argument is specified, [#2524](https://github.com/pydantic/pydantic/pull/2524) by @cwe5590 * Allow `collections.abc.Callable` to be used as type in Python 3.9, [#2519](https://github.com/pydantic/pydantic/pull/2519) by @daviskirk * Documentation update how to custom compile pydantic when using pip install, small change in `setup.py` to allow for custom CFLAGS when compiling, [#2517](https://github.com/pydantic/pydantic/pull/2517) by @peterroelants * remove side effect of `default_factory` to run it only once even if `Config.validate_all` is set, [#2515](https://github.com/pydantic/pydantic/pull/2515) by @PrettyWood * Add lookahead to ip regexes for `AnyUrl` hosts. This allows urls with DNS labels looking like IPs to validate as they are perfectly valid host names, [#2512](https://github.com/pydantic/pydantic/pull/2512) by @sbv-csis * Set `minItems` and `maxItems` in generated JSON schema for fixed-length tuples, [#2497](https://github.com/pydantic/pydantic/pull/2497) by @PrettyWood * Add `strict` argument to `conbytes`, [#2489](https://github.com/pydantic/pydantic/pull/2489) by @koxudaxi * Support user defined generic field types in generic models, [#2465](https://github.com/pydantic/pydantic/pull/2465) by @daviskirk * Add an example and a short explanation of subclassing `GetterDict` to docs, [#2463](https://github.com/pydantic/pydantic/pull/2463) by @nuno-andre * add `KafkaDsn` type, `HttpUrl` now has default port 80 for http and 443 for https, [#2447](https://github.com/pydantic/pydantic/pull/2447) by @MihanixA * Add `PastDate` and `FutureDate` types, [#2425](https://github.com/pydantic/pydantic/pull/2425) by @Kludex * Support generating schema for `Generic` fields with subtypes, [#2375](https://github.com/pydantic/pydantic/pull/2375) by @maximberg * fix(encoder): serialize `NameEmail` to str, [#2341](https://github.com/pydantic/pydantic/pull/2341) by @alecgerona * add `Config.smart_union` to prevent coercion in `Union` if possible, see [the doc](https://docs.pydantic.dev/usage/model_config/#smart-union) for more information, [#2092](https://github.com/pydantic/pydantic/pull/2092) by @PrettyWood * Add ability to use `typing.Counter` as a model field type, [#2060](https://github.com/pydantic/pydantic/pull/2060) by @uriyyo * Add parameterised subclasses to `__bases__` when constructing new parameterised classes, so that `A <: B => A[int] <: B[int]`, [#2007](https://github.com/pydantic/pydantic/pull/2007) by @diabolo-dan * Create `FileUrl` type that allows URLs that conform to [RFC 8089](https://tools.ietf.org/html/rfc8089#section-2). Add `host_required` parameter, which is `True` by default (`AnyUrl` and subclasses), `False` in `RedisDsn`, `FileUrl`, [#1983](https://github.com/pydantic/pydantic/pull/1983) by @vgerak * add `confrozenset()`, analogous to `conset()` and `conlist()`, [#1897](https://github.com/pydantic/pydantic/pull/1897) by @PrettyWood * stop calling parent class `root_validator` if overridden, [#1895](https://github.com/pydantic/pydantic/pull/1895) by @PrettyWood * Add `repr` (defaults to `True`) parameter to `Field`, to hide it from the default representation of the `BaseModel`, [#1831](https://github.com/pydantic/pydantic/pull/1831) by @fnep * Accept empty query/fragment URL parts, [#1807](https://github.com/pydantic/pydantic/pull/1807) by @xavier ## v1.8.2 (2021-05-11) !!! warning A security vulnerability, level "moderate" is fixed in v1.8.2. Please upgrade **ASAP**. See security advisory [CVE-2021-29510](https://github.com/pydantic/pydantic/security/advisories/GHSA-5jqp-qgf6-3pvh) * **Security fix:** Fix `date` and `datetime` parsing so passing either `'infinity'` or `float('inf')` (or their negative values) does not cause an infinite loop, see security advisory [CVE-2021-29510](https://github.com/pydantic/pydantic/security/advisories/GHSA-5jqp-qgf6-3pvh) * fix schema generation with Enum by generating a valid name, [#2575](https://github.com/pydantic/pydantic/pull/2575) by @PrettyWood * fix JSON schema generation with a `Literal` of an enum member, [#2536](https://github.com/pydantic/pydantic/pull/2536) by @PrettyWood * Fix bug with configurations declarations that are passed as keyword arguments during class creation, [#2532](https://github.com/pydantic/pydantic/pull/2532) by @uriyyo * Allow passing `json_encoders` in class kwargs, [#2521](https://github.com/pydantic/pydantic/pull/2521) by @layday * support arbitrary types with custom `__eq__`, [#2483](https://github.com/pydantic/pydantic/pull/2483) by @PrettyWood * support `Annotated` in `validate_arguments` and in generic models with Python 3.9, [#2483](https://github.com/pydantic/pydantic/pull/2483) by @PrettyWood ## v1.8.1 (2021-03-03) Bug fixes for regressions and new features from `v1.8` * allow elements of `Config.field` to update elements of a `Field`, [#2461](https://github.com/pydantic/pydantic/pull/2461) by @samuelcolvin * fix validation with a `BaseModel` field and a custom root type, [#2449](https://github.com/pydantic/pydantic/pull/2449) by @PrettyWood * expose `Pattern` encoder to `fastapi`, [#2444](https://github.com/pydantic/pydantic/pull/2444) by @PrettyWood * enable the Hypothesis plugin to generate a constrained float when the `multiple_of` argument is specified, [#2442](https://github.com/pydantic/pydantic/pull/2442) by @tobi-lipede-oodle * Avoid `RecursionError` when using some types like `Enum` or `Literal` with generic models, [#2436](https://github.com/pydantic/pydantic/pull/2436) by @PrettyWood * do not overwrite declared `__hash__` in subclasses of a model, [#2422](https://github.com/pydantic/pydantic/pull/2422) by @PrettyWood * fix `mypy` complaints on `Path` and `UUID` related custom types, [#2418](https://github.com/pydantic/pydantic/pull/2418) by @PrettyWood * Support properly variable length tuples of compound types, [#2416](https://github.com/pydantic/pydantic/pull/2416) by @PrettyWood ## v1.8 (2021-02-26) Thank you to pydantic's sponsors: @jorgecarleitao, @BCarley, @chdsbd, @tiangolo, @matin, @linusg, @kevinalh, @koxudaxi, @timdrijvers, @mkeen, @meadsteve, @ginomempin, @primer-io, @and-semakin, @tomthorogood, @AjitZK, @westonsteimel, @Mazyod, @christippett, @CarlosDomingues, @Kludex, @r-m-n for their kind support. ### Highlights * [Hypothesis plugin](https://docs.pydantic.dev/hypothesis_plugin/) for testing, [#2097](https://github.com/pydantic/pydantic/pull/2097) by @Zac-HD * support for [`NamedTuple` and `TypedDict`](https://docs.pydantic.dev/usage/types/#annotated-types), [#2216](https://github.com/pydantic/pydantic/pull/2216) by @PrettyWood * Support [`Annotated` hints on model fields](https://docs.pydantic.dev/usage/schema/#typingannotated-fields), [#2147](https://github.com/pydantic/pydantic/pull/2147) by @JacobHayes * [`frozen` parameter on `Config`](https://docs.pydantic.dev/usage/model_config/) to allow models to be hashed, [#1880](https://github.com/pydantic/pydantic/pull/1880) by @rhuille ### Changes * **Breaking Change**, remove old deprecation aliases from v1, [#2415](https://github.com/pydantic/pydantic/pull/2415) by @samuelcolvin: * remove notes on migrating to v1 in docs * remove `Schema` which was replaced by `Field` * remove `Config.case_insensitive` which was replaced by `Config.case_sensitive` (default `False`) * remove `Config.allow_population_by_alias` which was replaced by `Config.allow_population_by_field_name` * remove `model.fields` which was replaced by `model.__fields__` * remove `model.to_string()` which was replaced by `str(model)` * remove `model.__values__` which was replaced by `model.__dict__` * **Breaking Change:** always validate only first sublevel items with `each_item`. There were indeed some edge cases with some compound types where the validated items were the last sublevel ones, [#1933](https://github.com/pydantic/pydantic/pull/1933) by @PrettyWood * Update docs extensions to fix local syntax highlighting, [#2400](https://github.com/pydantic/pydantic/pull/2400) by @daviskirk * fix: allow `utils.lenient_issubclass` to handle `typing.GenericAlias` objects like `list[str]` in Python >= 3.9, [#2399](https://github.com/pydantic/pydantic/pull/2399) by @daviskirk * Improve field declaration for *pydantic* `dataclass` by allowing the usage of *pydantic* `Field` or `'metadata'` kwarg of `dataclasses.field`, [#2384](https://github.com/pydantic/pydantic/pull/2384) by @PrettyWood * Making `typing-extensions` a required dependency, [#2368](https://github.com/pydantic/pydantic/pull/2368) by @samuelcolvin * Make `resolve_annotations` more lenient, allowing for missing modules, [#2363](https://github.com/pydantic/pydantic/pull/2363) by @samuelcolvin * Allow configuring models through class kwargs, [#2356](https://github.com/pydantic/pydantic/pull/2356) by @Bobronium * Prevent `Mapping` subclasses from always being coerced to `dict`, [#2325](https://github.com/pydantic/pydantic/pull/2325) by @ofek * fix: allow `None` for type `Optional[conset / conlist]`, [#2320](https://github.com/pydantic/pydantic/pull/2320) by @PrettyWood * Support empty tuple type, [#2318](https://github.com/pydantic/pydantic/pull/2318) by @PrettyWood * fix: `python_requires` metadata to require >=3.6.1, [#2306](https://github.com/pydantic/pydantic/pull/2306) by @hukkinj1 * Properly encode `Decimal` with, or without any decimal places, [#2293](https://github.com/pydantic/pydantic/pull/2293) by @hultner * fix: update `__fields_set__` in `BaseModel.copy(update=…)`, [#2290](https://github.com/pydantic/pydantic/pull/2290) by @PrettyWood * fix: keep order of fields with `BaseModel.construct()`, [#2281](https://github.com/pydantic/pydantic/pull/2281) by @PrettyWood * Support generating schema for Generic fields, [#2262](https://github.com/pydantic/pydantic/pull/2262) by @maximberg * Fix `validate_decorator` so `**kwargs` doesn't exclude values when the keyword has the same name as the `*args` or `**kwargs` names, [#2251](https://github.com/pydantic/pydantic/pull/2251) by @cybojenix * Prevent overriding positional arguments with keyword arguments in `validate_arguments`, as per behaviour with native functions, [#2249](https://github.com/pydantic/pydantic/pull/2249) by @cybojenix * add documentation for `con*` type functions, [#2242](https://github.com/pydantic/pydantic/pull/2242) by @tayoogunbiyi * Support custom root type (aka `__root__`) when using `parse_obj()` with nested models, [#2238](https://github.com/pydantic/pydantic/pull/2238) by @PrettyWood * Support custom root type (aka `__root__`) with `from_orm()`, [#2237](https://github.com/pydantic/pydantic/pull/2237) by @PrettyWood * ensure cythonized functions are left untouched when creating models, based on [#1944](https://github.com/pydantic/pydantic/pull/1944) by @kollmats, [#2228](https://github.com/pydantic/pydantic/pull/2228) by @samuelcolvin * Resolve forward refs for stdlib dataclasses converted into *pydantic* ones, [#2220](https://github.com/pydantic/pydantic/pull/2220) by @PrettyWood * Add support for `NamedTuple` and `TypedDict` types. Those two types are now handled and validated when used inside `BaseModel` or *pydantic* `dataclass`. Two utils are also added `create_model_from_namedtuple` and `create_model_from_typeddict`, [#2216](https://github.com/pydantic/pydantic/pull/2216) by @PrettyWood * Do not ignore annotated fields when type is `Union[Type[...], ...]`, [#2213](https://github.com/pydantic/pydantic/pull/2213) by @PrettyWood * Raise a user-friendly `TypeError` when a `root_validator` does not return a `dict` (e.g. `None`), [#2209](https://github.com/pydantic/pydantic/pull/2209) by @masalim2 * Add a `FrozenSet[str]` type annotation to the `allowed_schemes` argument on the `strict_url` field type, [#2198](https://github.com/pydantic/pydantic/pull/2198) by @Midnighter * add `allow_mutation` constraint to `Field`, [#2195](https://github.com/pydantic/pydantic/pull/2195) by @sblack-usu * Allow `Field` with a `default_factory` to be used as an argument to a function decorated with `validate_arguments`, [#2176](https://github.com/pydantic/pydantic/pull/2176) by @thomascobb * Allow non-existent secrets directory by only issuing a warning, [#2175](https://github.com/pydantic/pydantic/pull/2175) by @davidolrik * fix URL regex to parse fragment without query string, [#2168](https://github.com/pydantic/pydantic/pull/2168) by @andrewmwhite * fix: ensure to always return one of the values in `Literal` field type, [#2166](https://github.com/pydantic/pydantic/pull/2166) by @PrettyWood * Support `typing.Annotated` hints on model fields. A `Field` may now be set in the type hint with `Annotated[..., Field(...)`; all other annotations are ignored but still visible with `get_type_hints(..., include_extras=True)`, [#2147](https://github.com/pydantic/pydantic/pull/2147) by @JacobHayes * Added `StrictBytes` type as well as `strict=False` option to `ConstrainedBytes`, [#2136](https://github.com/pydantic/pydantic/pull/2136) by @rlizzo * added `Config.anystr_lower` and `to_lower` kwarg to `constr` and `conbytes`, [#2134](https://github.com/pydantic/pydantic/pull/2134) by @tayoogunbiyi * Support plain `typing.Tuple` type, [#2132](https://github.com/pydantic/pydantic/pull/2132) by @PrettyWood * Add a bound method `validate` to functions decorated with `validate_arguments` to validate parameters without actually calling the function, [#2127](https://github.com/pydantic/pydantic/pull/2127) by @PrettyWood * Add the ability to customize settings sources (add / disable / change priority order), [#2107](https://github.com/pydantic/pydantic/pull/2107) by @kozlek * Fix mypy complaints about most custom *pydantic* types, [#2098](https://github.com/pydantic/pydantic/pull/2098) by @PrettyWood * Add a [Hypothesis](https://hypothesis.readthedocs.io/) plugin for easier [property-based testing](https://increment.com/testing/in-praise-of-property-based-testing/) with Pydantic's custom types - [usage details here](https://docs.pydantic.dev/hypothesis_plugin/), [#2097](https://github.com/pydantic/pydantic/pull/2097) by @Zac-HD * add validator for `None`, `NoneType` or `Literal[None]`, [#2095](https://github.com/pydantic/pydantic/pull/2095) by @PrettyWood * Handle properly fields of type `Callable` with a default value, [#2094](https://github.com/pydantic/pydantic/pull/2094) by @PrettyWood * Updated `create_model` return type annotation to return type which inherits from `__base__` argument, [#2071](https://github.com/pydantic/pydantic/pull/2071) by @uriyyo * Add merged `json_encoders` inheritance, [#2064](https://github.com/pydantic/pydantic/pull/2064) by @art049 * allow overwriting `ClassVar`s in sub-models without having to re-annotate them, [#2061](https://github.com/pydantic/pydantic/pull/2061) by @layday * add default encoder for `Pattern` type, [#2045](https://github.com/pydantic/pydantic/pull/2045) by @PrettyWood * Add `NonNegativeInt`, `NonPositiveInt`, `NonNegativeFloat`, `NonPositiveFloat`, [#1975](https://github.com/pydantic/pydantic/pull/1975) by @mdavis-xyz * Use % for percentage in string format of colors, [#1960](https://github.com/pydantic/pydantic/pull/1960) by @EdwardBetts * Fixed issue causing `KeyError` to be raised when building schema from multiple `BaseModel` with the same names declared in separate classes, [#1912](https://github.com/pydantic/pydantic/pull/1912) by @JSextonn * Add `rediss` (Redis over SSL) protocol to `RedisDsn` Allow URLs without `user` part (e.g., `rediss://:pass@localhost`), [#1911](https://github.com/pydantic/pydantic/pull/1911) by @TrDex * Add a new `frozen` boolean parameter to `Config` (default: `False`). Setting `frozen=True` does everything that `allow_mutation=False` does, and also generates a `__hash__()` method for the model. This makes instances of the model potentially hashable if all the attributes are hashable, [#1880](https://github.com/pydantic/pydantic/pull/1880) by @rhuille * fix schema generation with multiple Enums having the same name, [#1857](https://github.com/pydantic/pydantic/pull/1857) by @PrettyWood * Added support for 13/19 digits VISA credit cards in `PaymentCardNumber` type, [#1416](https://github.com/pydantic/pydantic/pull/1416) by @AlexanderSov * fix: prevent `RecursionError` while using recursive `GenericModel`s, [#1370](https://github.com/pydantic/pydantic/pull/1370) by @xppt * use `enum` for `typing.Literal` in JSON schema, [#1350](https://github.com/pydantic/pydantic/pull/1350) by @PrettyWood * Fix: some recursive models did not require `update_forward_refs` and silently behaved incorrectly, [#1201](https://github.com/pydantic/pydantic/pull/1201) by @PrettyWood * Fix bug where generic models with fields where the typevar is nested in another type `a: List[T]` are considered to be concrete. This allows these models to be subclassed and composed as expected, [#947](https://github.com/pydantic/pydantic/pull/947) by @daviskirk * Add `Config.copy_on_model_validation` flag. When set to `False`, *pydantic* will keep models used as fields untouched on validation instead of reconstructing (copying) them, [#265](https://github.com/pydantic/pydantic/pull/265) by @PrettyWood ## v1.7.4 (2021-05-11) * **Security fix:** Fix `date` and `datetime` parsing so passing either `'infinity'` or `float('inf')` (or their negative values) does not cause an infinite loop, See security advisory [CVE-2021-29510](https://github.com/pydantic/pydantic/security/advisories/GHSA-5jqp-qgf6-3pvh) ## v1.7.3 (2020-11-30) Thank you to pydantic's sponsors: @timdrijvers, @BCarley, @chdsbd, @tiangolo, @matin, @linusg, @kevinalh, @jorgecarleitao, @koxudaxi, @primer-api, @mkeen, @meadsteve for their kind support. * fix: set right default value for required (optional) fields, [#2142](https://github.com/pydantic/pydantic/pull/2142) by @PrettyWood * fix: support `underscore_attrs_are_private` with generic models, [#2138](https://github.com/pydantic/pydantic/pull/2138) by @PrettyWood * fix: update all modified field values in `root_validator` when `validate_assignment` is on, [#2116](https://github.com/pydantic/pydantic/pull/2116) by @PrettyWood * Allow pickling of `pydantic.dataclasses.dataclass` dynamically created from a built-in `dataclasses.dataclass`, [#2111](https://github.com/pydantic/pydantic/pull/2111) by @aimestereo * Fix a regression where Enum fields would not propagate keyword arguments to the schema, [#2109](https://github.com/pydantic/pydantic/pull/2109) by @bm424 * Ignore `__doc__` as private attribute when `Config.underscore_attrs_are_private` is set, [#2090](https://github.com/pydantic/pydantic/pull/2090) by @PrettyWood ## v1.7.2 (2020-11-01) * fix slow `GenericModel` concrete model creation, allow `GenericModel` concrete name reusing in module, [#2078](https://github.com/pydantic/pydantic/pull/2078) by @Bobronium * keep the order of the fields when `validate_assignment` is set, [#2073](https://github.com/pydantic/pydantic/pull/2073) by @PrettyWood * forward all the params of the stdlib `dataclass` when converted into *pydantic* `dataclass`, [#2065](https://github.com/pydantic/pydantic/pull/2065) by @PrettyWood ## v1.7.1 (2020-10-28) Thank you to pydantic's sponsors: @timdrijvers, @BCarley, @chdsbd, @tiangolo, @matin, @linusg, @kevinalh, @jorgecarleitao, @koxudaxi, @primer-api, @mkeen for their kind support. * fix annotation of `validate_arguments` when passing configuration as argument, [#2055](https://github.com/pydantic/pydantic/pull/2055) by @layday * Fix mypy assignment error when using `PrivateAttr`, [#2048](https://github.com/pydantic/pydantic/pull/2048) by @aphedges * fix `underscore_attrs_are_private` causing `TypeError` when overriding `__init__`, [#2047](https://github.com/pydantic/pydantic/pull/2047) by @samuelcolvin * Fixed regression introduced in v1.7 involving exception handling in field validators when `validate_assignment=True`, [#2044](https://github.com/pydantic/pydantic/pull/2044) by @johnsabath * fix: *pydantic* `dataclass` can inherit from stdlib `dataclass` and `Config.arbitrary_types_allowed` is supported, [#2042](https://github.com/pydantic/pydantic/pull/2042) by @PrettyWood ## v1.7 (2020-10-26) Thank you to pydantic's sponsors: @timdrijvers, @BCarley, @chdsbd, @tiangolo, @matin, @linusg, @kevinalh, @jorgecarleitao, @koxudaxi, @primer-api for their kind support. ### Highlights * Python 3.9 support, thanks @PrettyWood * [Private model attributes](https://docs.pydantic.dev/usage/models/#private-model-attributes), thanks @Bobronium * ["secrets files" support in `BaseSettings`](https://docs.pydantic.dev/usage/settings/#secret-support), thanks @mdgilene * [convert stdlib dataclasses to pydantic dataclasses and use stdlib dataclasses in models](https://docs.pydantic.dev/usage/dataclasses/#stdlib-dataclasses-and-pydantic-dataclasses), thanks @PrettyWood ### Changes * **Breaking Change:** remove `__field_defaults__`, add `default_factory` support with `BaseModel.construct`. Use `.get_default()` method on fields in `__fields__` attribute instead, [#1732](https://github.com/pydantic/pydantic/pull/1732) by @PrettyWood * Rearrange CI to run linting as a separate job, split install recipes for different tasks, [#2020](https://github.com/pydantic/pydantic/pull/2020) by @samuelcolvin * Allows subclasses of generic models to make some, or all, of the superclass's type parameters concrete, while also defining new type parameters in the subclass, [#2005](https://github.com/pydantic/pydantic/pull/2005) by @choogeboom * Call validator with the correct `values` parameter type in `BaseModel.__setattr__`, when `validate_assignment = True` in model config, [#1999](https://github.com/pydantic/pydantic/pull/1999) by @me-ransh * Force `fields.Undefined` to be a singleton object, fixing inherited generic model schemas, [#1981](https://github.com/pydantic/pydantic/pull/1981) by @daviskirk * Include tests in source distributions, [#1976](https://github.com/pydantic/pydantic/pull/1976) by @sbraz * Add ability to use `min_length/max_length` constraints with secret types, [#1974](https://github.com/pydantic/pydantic/pull/1974) by @uriyyo * Also check `root_validators` when `validate_assignment` is on, [#1971](https://github.com/pydantic/pydantic/pull/1971) by @PrettyWood * Fix const validators not running when custom validators are present, [#1957](https://github.com/pydantic/pydantic/pull/1957) by @hmvp * add `deque` to field types, [#1935](https://github.com/pydantic/pydantic/pull/1935) by @wozniakty * add basic support for Python 3.9, [#1832](https://github.com/pydantic/pydantic/pull/1832) by @PrettyWood * Fix typo in the anchor of exporting_models.md#modelcopy and incorrect description, [#1821](https://github.com/pydantic/pydantic/pull/1821) by @KimMachineGun * Added ability for `BaseSettings` to read "secret files", [#1820](https://github.com/pydantic/pydantic/pull/1820) by @mdgilene * add `parse_raw_as` utility function, [#1812](https://github.com/pydantic/pydantic/pull/1812) by @PrettyWood * Support home directory relative paths for `dotenv` files (e.g. `~/.env`), [#1803](https://github.com/pydantic/pydantic/pull/1803) by @PrettyWood * Clarify documentation for `parse_file` to show that the argument should be a file *path* not a file-like object, [#1794](https://github.com/pydantic/pydantic/pull/1794) by @mdavis-xyz * Fix false positive from mypy plugin when a class nested within a `BaseModel` is named `Model`, [#1770](https://github.com/pydantic/pydantic/pull/1770) by @selimb * add basic support of Pattern type in schema generation, [#1767](https://github.com/pydantic/pydantic/pull/1767) by @PrettyWood * Support custom title, description and default in schema of enums, [#1748](https://github.com/pydantic/pydantic/pull/1748) by @PrettyWood * Properly represent `Literal` Enums when `use_enum_values` is True, [#1747](https://github.com/pydantic/pydantic/pull/1747) by @noelevans * Allows timezone information to be added to strings to be formatted as time objects. Permitted formats are `Z` for UTC or an offset for absolute positive or negative time shifts. Or the timezone data can be omitted, [#1744](https://github.com/pydantic/pydantic/pull/1744) by @noelevans * Add stub `__init__` with Python 3.6 signature for `ForwardRef`, [#1738](https://github.com/pydantic/pydantic/pull/1738) by @sirtelemak * Fix behaviour with forward refs and optional fields in nested models, [#1736](https://github.com/pydantic/pydantic/pull/1736) by @PrettyWood * add `Enum` and `IntEnum` as valid types for fields, [#1735](https://github.com/pydantic/pydantic/pull/1735) by @PrettyWood * Change default value of `__module__` argument of `create_model` from `None` to `'pydantic.main'`. Set reference of created concrete model to it's module to allow pickling (not applied to models created in functions), [#1686](https://github.com/pydantic/pydantic/pull/1686) by @Bobronium * Add private attributes support, [#1679](https://github.com/pydantic/pydantic/pull/1679) by @Bobronium * add `config` to `@validate_arguments`, [#1663](https://github.com/pydantic/pydantic/pull/1663) by @samuelcolvin * Allow descendant Settings models to override env variable names for the fields defined in parent Settings models with `env` in their `Config`. Previously only `env_prefix` configuration option was applicable, [#1561](https://github.com/pydantic/pydantic/pull/1561) by @ojomio * Support `ref_template` when creating schema `$ref`s, [#1479](https://github.com/pydantic/pydantic/pull/1479) by @kilo59 * Add a `__call__` stub to `PyObject` so that mypy will know that it is callable, [#1352](https://github.com/pydantic/pydantic/pull/1352) by @brianmaissy * `pydantic.dataclasses.dataclass` decorator now supports built-in `dataclasses.dataclass`. It is hence possible to convert an existing `dataclass` easily to add Pydantic validation. Moreover nested dataclasses are also supported, [#744](https://github.com/pydantic/pydantic/pull/744) by @PrettyWood ## v1.6.2 (2021-05-11) * **Security fix:** Fix `date` and `datetime` parsing so passing either `'infinity'` or `float('inf')` (or their negative values) does not cause an infinite loop, See security advisory [CVE-2021-29510](https://github.com/pydantic/pydantic/security/advisories/GHSA-5jqp-qgf6-3pvh) ## v1.6.1 (2020-07-15) * fix validation and parsing of nested models with `default_factory`, [#1710](https://github.com/pydantic/pydantic/pull/1710) by @PrettyWood ## v1.6 (2020-07-11) Thank you to pydantic's sponsors: @matin, @tiangolo, @chdsbd, @jorgecarleitao, and 1 anonymous sponsor for their kind support. * Modify validators for `conlist` and `conset` to not have `always=True`, [#1682](https://github.com/pydantic/pydantic/pull/1682) by @samuelcolvin * add port check to `AnyUrl` (can't exceed 65536) ports are 16 unsigned bits: `0 <= port <= 2**16-1` src: [rfc793 header format](https://tools.ietf.org/html/rfc793#section-3.1), [#1654](https://github.com/pydantic/pydantic/pull/1654) by @flapili * Document default `regex` anchoring semantics, [#1648](https://github.com/pydantic/pydantic/pull/1648) by @yurikhan * Use `chain.from_iterable` in class_validators.py. This is a faster and more idiomatic way of using `itertools.chain`. Instead of computing all the items in the iterable and storing them in memory, they are computed one-by-one and never stored as a huge list. This can save on both runtime and memory space, [#1642](https://github.com/pydantic/pydantic/pull/1642) by @cool-RR * Add `conset()`, analogous to `conlist()`, [#1623](https://github.com/pydantic/pydantic/pull/1623) by @patrickkwang * make Pydantic errors (un)pickable, [#1616](https://github.com/pydantic/pydantic/pull/1616) by @PrettyWood * Allow custom encoding for `dotenv` files, [#1615](https://github.com/pydantic/pydantic/pull/1615) by @PrettyWood * Ensure `SchemaExtraCallable` is always defined to get type hints on BaseConfig, [#1614](https://github.com/pydantic/pydantic/pull/1614) by @PrettyWood * Update datetime parser to support negative timestamps, [#1600](https://github.com/pydantic/pydantic/pull/1600) by @mlbiche * Update mypy, remove `AnyType` alias for `Type[Any]`, [#1598](https://github.com/pydantic/pydantic/pull/1598) by @samuelcolvin * Adjust handling of root validators so that errors are aggregated from *all* failing root validators, instead of reporting on only the first root validator to fail, [#1586](https://github.com/pydantic/pydantic/pull/1586) by @beezee * Make `__modify_schema__` on Enums apply to the enum schema rather than fields that use the enum, [#1581](https://github.com/pydantic/pydantic/pull/1581) by @therefromhere * Fix behavior of `__all__` key when used in conjunction with index keys in advanced include/exclude of fields that are sequences, [#1579](https://github.com/pydantic/pydantic/pull/1579) by @xspirus * Subclass validators do not run when referencing a `List` field defined in a parent class when `each_item=True`. Added an example to the docs illustrating this, [#1566](https://github.com/pydantic/pydantic/pull/1566) by @samueldeklund * change `schema.field_class_to_schema` to support `frozenset` in schema, [#1557](https://github.com/pydantic/pydantic/pull/1557) by @wangpeibao * Call `__modify_schema__` only for the field schema, [#1552](https://github.com/pydantic/pydantic/pull/1552) by @PrettyWood * Move the assignment of `field.validate_always` in `fields.py` so the `always` parameter of validators work on inheritance, [#1545](https://github.com/pydantic/pydantic/pull/1545) by @dcHHH * Added support for UUID instantiation through 16 byte strings such as `b'\x12\x34\x56\x78' * 4`. This was done to support `BINARY(16)` columns in sqlalchemy, [#1541](https://github.com/pydantic/pydantic/pull/1541) by @shawnwall * Add a test assertion that `default_factory` can return a singleton, [#1523](https://github.com/pydantic/pydantic/pull/1523) by @therefromhere * Add `NameEmail.__eq__` so duplicate `NameEmail` instances are evaluated as equal, [#1514](https://github.com/pydantic/pydantic/pull/1514) by @stephen-bunn * Add datamodel-code-generator link in pydantic document site, [#1500](https://github.com/pydantic/pydantic/pull/1500) by @koxudaxi * Added a "Discussion of Pydantic" section to the documentation, with a link to "Pydantic Introduction" video by Alexander Hultnér, [#1499](https://github.com/pydantic/pydantic/pull/1499) by @hultner * Avoid some side effects of `default_factory` by calling it only once if possible and by not setting a default value in the schema, [#1491](https://github.com/pydantic/pydantic/pull/1491) by @PrettyWood * Added docs about dumping dataclasses to JSON, [#1487](https://github.com/pydantic/pydantic/pull/1487) by @mikegrima * Make `BaseModel.__signature__` class-only, so getting `__signature__` from model instance will raise `AttributeError`, [#1466](https://github.com/pydantic/pydantic/pull/1466) by @Bobronium * include `'format': 'password'` in the schema for secret types, [#1424](https://github.com/pydantic/pydantic/pull/1424) by @atheuz * Modify schema constraints on `ConstrainedFloat` so that `exclusiveMinimum` and minimum are not included in the schema if they are equal to `-math.inf` and `exclusiveMaximum` and `maximum` are not included if they are equal to `math.inf`, [#1417](https://github.com/pydantic/pydantic/pull/1417) by @vdwees * Squash internal `__root__` dicts in `.dict()` (and, by extension, in `.json()`), [#1414](https://github.com/pydantic/pydantic/pull/1414) by @patrickkwang * Move `const` validator to post-validators so it validates the parsed value, [#1410](https://github.com/pydantic/pydantic/pull/1410) by @selimb * Fix model validation to handle nested literals, e.g. `Literal['foo', Literal['bar']]`, [#1364](https://github.com/pydantic/pydantic/pull/1364) by @DBCerigo * Remove `user_required = True` from `RedisDsn`, neither user nor password are required, [#1275](https://github.com/pydantic/pydantic/pull/1275) by @samuelcolvin * Remove extra `allOf` from schema for fields with `Union` and custom `Field`, [#1209](https://github.com/pydantic/pydantic/pull/1209) by @mostaphaRoudsari * Updates OpenAPI schema generation to output all enums as separate models. Instead of inlining the enum values in the model schema, models now use a `$ref` property to point to the enum definition, [#1173](https://github.com/pydantic/pydantic/pull/1173) by @calvinwyoung ## v1.5.1 (2020-04-23) * Signature generation with `extra: allow` never uses a field name, [#1418](https://github.com/pydantic/pydantic/pull/1418) by @prettywood * Avoid mutating `Field` default value, [#1412](https://github.com/pydantic/pydantic/pull/1412) by @prettywood ## v1.5 (2020-04-18) * Make includes/excludes arguments for `.dict()`, `._iter()`, ..., immutable, [#1404](https://github.com/pydantic/pydantic/pull/1404) by @AlexECX * Always use a field's real name with includes/excludes in `model._iter()`, regardless of `by_alias`, [#1397](https://github.com/pydantic/pydantic/pull/1397) by @AlexECX * Update constr regex example to include start and end lines, [#1396](https://github.com/pydantic/pydantic/pull/1396) by @lmcnearney * Confirm that shallow `model.copy()` does make a shallow copy of attributes, [#1383](https://github.com/pydantic/pydantic/pull/1383) by @samuelcolvin * Renaming `model_name` argument of `main.create_model()` to `__model_name` to allow using `model_name` as a field name, [#1367](https://github.com/pydantic/pydantic/pull/1367) by @kittipatv * Replace raising of exception to silent passing for non-Var attributes in mypy plugin, [#1345](https://github.com/pydantic/pydantic/pull/1345) by @b0g3r * Remove `typing_extensions` dependency for Python 3.8, [#1342](https://github.com/pydantic/pydantic/pull/1342) by @prettywood * Make `SecretStr` and `SecretBytes` initialization idempotent, [#1330](https://github.com/pydantic/pydantic/pull/1330) by @atheuz * document making secret types dumpable using the json method, [#1328](https://github.com/pydantic/pydantic/pull/1328) by @atheuz * Move all testing and build to github actions, add windows and macos binaries, thank you @StephenBrown2 for much help, [#1326](https://github.com/pydantic/pydantic/pull/1326) by @samuelcolvin * fix card number length check in `PaymentCardNumber`, `PaymentCardBrand` now inherits from `str`, [#1317](https://github.com/pydantic/pydantic/pull/1317) by @samuelcolvin * Have `BaseModel` inherit from `Representation` to make mypy happy when overriding `__str__`, [#1310](https://github.com/pydantic/pydantic/pull/1310) by @FuegoFro * Allow `None` as input to all optional list fields, [#1307](https://github.com/pydantic/pydantic/pull/1307) by @prettywood * Add `datetime` field to `default_factory` example, [#1301](https://github.com/pydantic/pydantic/pull/1301) by @StephenBrown2 * Allow subclasses of known types to be encoded with superclass encoder, [#1291](https://github.com/pydantic/pydantic/pull/1291) by @StephenBrown2 * Exclude exported fields from all elements of a list/tuple of submodels/dicts with `'__all__'`, [#1286](https://github.com/pydantic/pydantic/pull/1286) by @masalim2 * Add pydantic.color.Color objects as available input for Color fields, [#1258](https://github.com/pydantic/pydantic/pull/1258) by @leosussan * In examples, type nullable fields as `Optional`, so that these are valid mypy annotations, [#1248](https://github.com/pydantic/pydantic/pull/1248) by @kokes * Make `pattern_validator()` accept pre-compiled `Pattern` objects. Fix `str_validator()` return type to `str`, [#1237](https://github.com/pydantic/pydantic/pull/1237) by @adamgreg * Document how to manage Generics and inheritance, [#1229](https://github.com/pydantic/pydantic/pull/1229) by @esadruhn * `update_forward_refs()` method of BaseModel now copies `__dict__` of class module instead of modifying it, [#1228](https://github.com/pydantic/pydantic/pull/1228) by @paul-ilyin * Support instance methods and class methods with `@validate_arguments`, [#1222](https://github.com/pydantic/pydantic/pull/1222) by @samuelcolvin * Add `default_factory` argument to `Field` to create a dynamic default value by passing a zero-argument callable, [#1210](https://github.com/pydantic/pydantic/pull/1210) by @prettywood * add support for `NewType` of `List`, `Optional`, etc, [#1207](https://github.com/pydantic/pydantic/pull/1207) by @Kazy * fix mypy signature for `root_validator`, [#1192](https://github.com/pydantic/pydantic/pull/1192) by @samuelcolvin * Fixed parsing of nested 'custom root type' models, [#1190](https://github.com/pydantic/pydantic/pull/1190) by @Shados * Add `validate_arguments` function decorator which checks the arguments to a function matches type annotations, [#1179](https://github.com/pydantic/pydantic/pull/1179) by @samuelcolvin * Add `__signature__` to models, [#1034](https://github.com/pydantic/pydantic/pull/1034) by @Bobronium * Refactor `._iter()` method, 10x speed boost for `dict(model)`, [#1017](https://github.com/pydantic/pydantic/pull/1017) by @Bobronium ## v1.4 (2020-01-24) * **Breaking Change:** alias precedence logic changed so aliases on a field always take priority over an alias from `alias_generator` to avoid buggy/unexpected behaviour, see [here](https://docs.pydantic.dev/usage/model_config/#alias-precedence) for details, [#1178](https://github.com/pydantic/pydantic/pull/1178) by @samuelcolvin * Add support for unicode and punycode in TLDs, [#1182](https://github.com/pydantic/pydantic/pull/1182) by @jamescurtin * Fix `cls` argument in validators during assignment, [#1172](https://github.com/pydantic/pydantic/pull/1172) by @samuelcolvin * completing Luhn algorithm for `PaymentCardNumber`, [#1166](https://github.com/pydantic/pydantic/pull/1166) by @cuencandres * add support for generics that implement `__get_validators__` like a custom data type, [#1159](https://github.com/pydantic/pydantic/pull/1159) by @tiangolo * add support for infinite generators with `Iterable`, [#1152](https://github.com/pydantic/pydantic/pull/1152) by @tiangolo * fix `url_regex` to accept schemas with `+`, `-` and `.` after the first character, [#1142](https://github.com/pydantic/pydantic/pull/1142) by @samuelcolvin * move `version_info()` to `version.py`, suggest its use in issues, [#1138](https://github.com/pydantic/pydantic/pull/1138) by @samuelcolvin * Improve pydantic import time by roughly 50% by deferring some module loading and regex compilation, [#1127](https://github.com/pydantic/pydantic/pull/1127) by @samuelcolvin * Fix `EmailStr` and `NameEmail` to accept instances of themselves in cython, [#1126](https://github.com/pydantic/pydantic/pull/1126) by @koxudaxi * Pass model class to the `Config.schema_extra` callable, [#1125](https://github.com/pydantic/pydantic/pull/1125) by @therefromhere * Fix regex for username and password in URLs, [#1115](https://github.com/pydantic/pydantic/pull/1115) by @samuelcolvin * Add support for nested generic models, [#1104](https://github.com/pydantic/pydantic/pull/1104) by @dmontagu * add `__all__` to `__init__.py` to prevent "implicit reexport" errors from mypy, [#1072](https://github.com/pydantic/pydantic/pull/1072) by @samuelcolvin * Add support for using "dotenv" files with `BaseSettings`, [#1011](https://github.com/pydantic/pydantic/pull/1011) by @acnebs ## v1.3 (2019-12-21) * Change `schema` and `schema_model` to handle dataclasses by using their `__pydantic_model__` feature, [#792](https://github.com/pydantic/pydantic/pull/792) by @aviramha * Added option for `root_validator` to be skipped if values validation fails using keyword `skip_on_failure=True`, [#1049](https://github.com/pydantic/pydantic/pull/1049) by @aviramha * Allow `Config.schema_extra` to be a callable so that the generated schema can be post-processed, [#1054](https://github.com/pydantic/pydantic/pull/1054) by @selimb * Update mypy to version 0.750, [#1057](https://github.com/pydantic/pydantic/pull/1057) by @dmontagu * Trick Cython into allowing str subclassing, [#1061](https://github.com/pydantic/pydantic/pull/1061) by @skewty * Prevent type attributes being added to schema unless the attribute `__schema_attributes__` is `True`, [#1064](https://github.com/pydantic/pydantic/pull/1064) by @samuelcolvin * Change `BaseModel.parse_file` to use `Config.json_loads`, [#1067](https://github.com/pydantic/pydantic/pull/1067) by @kierandarcy * Fix for optional `Json` fields, [#1073](https://github.com/pydantic/pydantic/pull/1073) by @volker48 * Change the default number of threads used when compiling with cython to one, allow override via the `CYTHON_NTHREADS` environment variable, [#1074](https://github.com/pydantic/pydantic/pull/1074) by @samuelcolvin * Run FastAPI tests during Pydantic's CI tests, [#1075](https://github.com/pydantic/pydantic/pull/1075) by @tiangolo * My mypy strictness constraints, and associated tweaks to type annotations, [#1077](https://github.com/pydantic/pydantic/pull/1077) by @samuelcolvin * Add `__eq__` to SecretStr and SecretBytes to allow "value equals", [#1079](https://github.com/pydantic/pydantic/pull/1079) by @sbv-trueenergy * Fix schema generation for nested None case, [#1088](https://github.com/pydantic/pydantic/pull/1088) by @lutostag * Consistent checks for sequence like objects, [#1090](https://github.com/pydantic/pydantic/pull/1090) by @samuelcolvin * Fix `Config` inheritance on `BaseSettings` when used with `env_prefix`, [#1091](https://github.com/pydantic/pydantic/pull/1091) by @samuelcolvin * Fix for `__modify_schema__` when it conflicted with `field_class_to_schema*`, [#1102](https://github.com/pydantic/pydantic/pull/1102) by @samuelcolvin * docs: Fix explanation of case sensitive environment variable names when populating `BaseSettings` subclass attributes, [#1105](https://github.com/pydantic/pydantic/pull/1105) by @tribals * Rename django-rest-framework benchmark in documentation, [#1119](https://github.com/pydantic/pydantic/pull/1119) by @frankie567 ## v1.2 (2019-11-28) * **Possible Breaking Change:** Add support for required `Optional` with `name: Optional[AnyType] = Field(...)` and refactor `ModelField` creation to preserve `required` parameter value, [#1031](https://github.com/pydantic/pydantic/pull/1031) by @tiangolo; see [here](https://docs.pydantic.dev/usage/models/#required-optional-fields) for details * Add benchmarks for `cattrs`, [#513](https://github.com/pydantic/pydantic/pull/513) by @sebastianmika * Add `exclude_none` option to `dict()` and friends, [#587](https://github.com/pydantic/pydantic/pull/587) by @niknetniko * Add benchmarks for `valideer`, [#670](https://github.com/pydantic/pydantic/pull/670) by @gsakkis * Add `parse_obj_as` and `parse_file_as` functions for ad-hoc parsing of data into arbitrary pydantic-compatible types, [#934](https://github.com/pydantic/pydantic/pull/934) by @dmontagu * Add `allow_reuse` argument to validators, thus allowing validator reuse, [#940](https://github.com/pydantic/pydantic/pull/940) by @dmontagu * Add support for mapping types for custom root models, [#958](https://github.com/pydantic/pydantic/pull/958) by @dmontagu * Mypy plugin support for dataclasses, [#966](https://github.com/pydantic/pydantic/pull/966) by @koxudaxi * Add support for dataclasses default factory, [#968](https://github.com/pydantic/pydantic/pull/968) by @ahirner * Add a `ByteSize` type for converting byte string (`1GB`) to plain bytes, [#977](https://github.com/pydantic/pydantic/pull/977) by @dgasmith * Fix mypy complaint about `@root_validator(pre=True)`, [#984](https://github.com/pydantic/pydantic/pull/984) by @samuelcolvin * Add manylinux binaries for Python 3.8 to pypi, also support manylinux2010, [#994](https://github.com/pydantic/pydantic/pull/994) by @samuelcolvin * Adds ByteSize conversion to another unit, [#995](https://github.com/pydantic/pydantic/pull/995) by @dgasmith * Fix `__str__` and `__repr__` inheritance for models, [#1022](https://github.com/pydantic/pydantic/pull/1022) by @samuelcolvin * add testimonials section to docs, [#1025](https://github.com/pydantic/pydantic/pull/1025) by @sullivancolin * Add support for `typing.Literal` for Python 3.8, [#1026](https://github.com/pydantic/pydantic/pull/1026) by @dmontagu ## v1.1.1 (2019-11-20) * Fix bug where use of complex fields on sub-models could cause fields to be incorrectly configured, [#1015](https://github.com/pydantic/pydantic/pull/1015) by @samuelcolvin ## v1.1 (2019-11-07) * Add a mypy plugin for type checking `BaseModel.__init__` and more, [#722](https://github.com/pydantic/pydantic/pull/722) by @dmontagu * Change return type typehint for `GenericModel.__class_getitem__` to prevent PyCharm warnings, [#936](https://github.com/pydantic/pydantic/pull/936) by @dmontagu * Fix usage of `Any` to allow `None`, also support `TypeVar` thus allowing use of un-parameterised collection types e.g. `Dict` and `List`, [#962](https://github.com/pydantic/pydantic/pull/962) by @samuelcolvin * Set `FieldInfo` on subfields to fix schema generation for complex nested types, [#965](https://github.com/pydantic/pydantic/pull/965) by @samuelcolvin ## v1.0 (2019-10-23) * **Breaking Change:** deprecate the `Model.fields` property, use `Model.__fields__` instead, [#883](https://github.com/pydantic/pydantic/pull/883) by @samuelcolvin * **Breaking Change:** Change the precedence of aliases so child model aliases override parent aliases, including using `alias_generator`, [#904](https://github.com/pydantic/pydantic/pull/904) by @samuelcolvin * **Breaking change:** Rename `skip_defaults` to `exclude_unset`, and add ability to exclude actual defaults, [#915](https://github.com/pydantic/pydantic/pull/915) by @dmontagu * Add `**kwargs` to `pydantic.main.ModelMetaclass.__new__` so `__init_subclass__` can take custom parameters on extended `BaseModel` classes, [#867](https://github.com/pydantic/pydantic/pull/867) by @retnikt * Fix field of a type that has a default value, [#880](https://github.com/pydantic/pydantic/pull/880) by @koxudaxi * Use `FutureWarning` instead of `DeprecationWarning` when `alias` instead of `env` is used for settings models, [#881](https://github.com/pydantic/pydantic/pull/881) by @samuelcolvin * Fix issue with `BaseSettings` inheritance and `alias` getting set to `None`, [#882](https://github.com/pydantic/pydantic/pull/882) by @samuelcolvin * Modify `__repr__` and `__str__` methods to be consistent across all public classes, add `__pretty__` to support python-devtools, [#884](https://github.com/pydantic/pydantic/pull/884) by @samuelcolvin * deprecation warning for `case_insensitive` on `BaseSettings` config, [#885](https://github.com/pydantic/pydantic/pull/885) by @samuelcolvin * For `BaseSettings` merge environment variables and in-code values recursively, as long as they create a valid object when merged together, to allow splitting init arguments, [#888](https://github.com/pydantic/pydantic/pull/888) by @idmitrievsky * change secret types example, [#890](https://github.com/pydantic/pydantic/pull/890) by @ashears * Change the signature of `Model.construct()` to be more user-friendly, document `construct()` usage, [#898](https://github.com/pydantic/pydantic/pull/898) by @samuelcolvin * Add example for the `construct()` method, [#907](https://github.com/pydantic/pydantic/pull/907) by @ashears * Improve use of `Field` constraints on complex types, raise an error if constraints are not enforceable, also support tuples with an ellipsis `Tuple[X, ...]`, `Sequence` and `FrozenSet` in schema, [#909](https://github.com/pydantic/pydantic/pull/909) by @samuelcolvin * update docs for bool missing valid value, [#911](https://github.com/pydantic/pydantic/pull/911) by @trim21 * Better `str`/`repr` logic for `ModelField`, [#912](https://github.com/pydantic/pydantic/pull/912) by @samuelcolvin * Fix `ConstrainedList`, update schema generation to reflect `min_items` and `max_items` `Field()` arguments, [#917](https://github.com/pydantic/pydantic/pull/917) by @samuelcolvin * Allow abstracts sets (eg. dict keys) in the `include` and `exclude` arguments of `dict()`, [#921](https://github.com/pydantic/pydantic/pull/921) by @samuelcolvin * Fix JSON serialization errors on `ValidationError.json()` by using `pydantic_encoder`, [#922](https://github.com/pydantic/pydantic/pull/922) by @samuelcolvin * Clarify usage of `remove_untouched`, improve error message for types with no validators, [#926](https://github.com/pydantic/pydantic/pull/926) by @retnikt ## v1.0b2 (2019-10-07) * Mark `StrictBool` typecheck as `bool` to allow for default values without mypy errors, [#690](https://github.com/pydantic/pydantic/pull/690) by @dmontagu * Transfer the documentation build from sphinx to mkdocs, re-write much of the documentation, [#856](https://github.com/pydantic/pydantic/pull/856) by @samuelcolvin * Add support for custom naming schemes for `GenericModel` subclasses, [#859](https://github.com/pydantic/pydantic/pull/859) by @dmontagu * Add `if TYPE_CHECKING:` to the excluded lines for test coverage, [#874](https://github.com/pydantic/pydantic/pull/874) by @dmontagu * Rename `allow_population_by_alias` to `allow_population_by_field_name`, remove unnecessary warning about it, [#875](https://github.com/pydantic/pydantic/pull/875) by @samuelcolvin ## v1.0b1 (2019-10-01) * **Breaking Change:** rename `Schema` to `Field`, make it a function to placate mypy, [#577](https://github.com/pydantic/pydantic/pull/577) by @samuelcolvin * **Breaking Change:** modify parsing behavior for `bool`, [#617](https://github.com/pydantic/pydantic/pull/617) by @dmontagu * **Breaking Change:** `get_validators` is no longer recognised, use `__get_validators__`. `Config.ignore_extra` and `Config.allow_extra` are no longer recognised, use `Config.extra`, [#720](https://github.com/pydantic/pydantic/pull/720) by @samuelcolvin * **Breaking Change:** modify default config settings for `BaseSettings`; `case_insensitive` renamed to `case_sensitive`, default changed to `case_sensitive = False`, `env_prefix` default changed to `''` - e.g. no prefix, [#721](https://github.com/pydantic/pydantic/pull/721) by @dmontagu * **Breaking change:** Implement `root_validator` and rename root errors from `__obj__` to `__root__`, [#729](https://github.com/pydantic/pydantic/pull/729) by @samuelcolvin * **Breaking Change:** alter the behaviour of `dict(model)` so that sub-models are no longer converted to dictionaries, [#733](https://github.com/pydantic/pydantic/pull/733) by @samuelcolvin * **Breaking change:** Added `initvars` support to `post_init_post_parse`, [#748](https://github.com/pydantic/pydantic/pull/748) by @Raphael-C-Almeida * **Breaking Change:** Make `BaseModel.json()` only serialize the `__root__` key for models with custom root, [#752](https://github.com/pydantic/pydantic/pull/752) by @dmontagu * **Breaking Change:** complete rewrite of `URL` parsing logic, [#755](https://github.com/pydantic/pydantic/pull/755) by @samuelcolvin * **Breaking Change:** preserve superclass annotations for field-determination when not provided in subclass, [#757](https://github.com/pydantic/pydantic/pull/757) by @dmontagu * **Breaking Change:** `BaseSettings` now uses the special `env` settings to define which environment variables to read, not aliases, [#847](https://github.com/pydantic/pydantic/pull/847) by @samuelcolvin * add support for `assert` statements inside validators, [#653](https://github.com/pydantic/pydantic/pull/653) by @abdusco * Update documentation to specify the use of `pydantic.dataclasses.dataclass` and subclassing `pydantic.BaseModel`, [#710](https://github.com/pydantic/pydantic/pull/710) by @maddosaurus * Allow custom JSON decoding and encoding via `json_loads` and `json_dumps` `Config` properties, [#714](https://github.com/pydantic/pydantic/pull/714) by @samuelcolvin * make all annotated fields occur in the order declared, [#715](https://github.com/pydantic/pydantic/pull/715) by @dmontagu * use pytest to test `mypy` integration, [#735](https://github.com/pydantic/pydantic/pull/735) by @dmontagu * add `__repr__` method to `ErrorWrapper`, [#738](https://github.com/pydantic/pydantic/pull/738) by @samuelcolvin * Added support for `FrozenSet` members in dataclasses, and a better error when attempting to use types from the `typing` module that are not supported by Pydantic, [#745](https://github.com/pydantic/pydantic/pull/745) by @djpetti * add documentation for Pycharm Plugin, [#750](https://github.com/pydantic/pydantic/pull/750) by @koxudaxi * fix broken examples in the docs, [#753](https://github.com/pydantic/pydantic/pull/753) by @dmontagu * moving typing related objects into `pydantic.typing`, [#761](https://github.com/pydantic/pydantic/pull/761) by @samuelcolvin * Minor performance improvements to `ErrorWrapper`, `ValidationError` and datetime parsing, [#763](https://github.com/pydantic/pydantic/pull/763) by @samuelcolvin * Improvements to `datetime`/`date`/`time`/`timedelta` types: more descriptive errors, change errors to `value_error` not `type_error`, support bytes, [#766](https://github.com/pydantic/pydantic/pull/766) by @samuelcolvin * fix error messages for `Literal` types with multiple allowed values, [#770](https://github.com/pydantic/pydantic/pull/770) by @dmontagu * Improved auto-generated `title` field in JSON schema by converting underscore to space, [#772](https://github.com/pydantic/pydantic/pull/772) by @skewty * support `mypy --no-implicit-reexport` for dataclasses, also respect `--no-implicit-reexport` in pydantic itself, [#783](https://github.com/pydantic/pydantic/pull/783) by @samuelcolvin * add the `PaymentCardNumber` type, [#790](https://github.com/pydantic/pydantic/pull/790) by @matin * Fix const validations for lists, [#794](https://github.com/pydantic/pydantic/pull/794) by @hmvp * Set `additionalProperties` to false in schema for models with extra fields disallowed, [#796](https://github.com/pydantic/pydantic/pull/796) by @Code0x58 * `EmailStr` validation method now returns local part case-sensitive per RFC 5321, [#798](https://github.com/pydantic/pydantic/pull/798) by @henriklindgren * Added ability to validate strictness to `ConstrainedFloat`, `ConstrainedInt` and `ConstrainedStr` and added `StrictFloat` and `StrictInt` classes, [#799](https://github.com/pydantic/pydantic/pull/799) by @DerRidda * Improve handling of `None` and `Optional`, replace `whole` with `each_item` (inverse meaning, default `False`) on validators, [#803](https://github.com/pydantic/pydantic/pull/803) by @samuelcolvin * add support for `Type[T]` type hints, [#807](https://github.com/pydantic/pydantic/pull/807) by @timonbimon * Performance improvements from removing `change_exceptions`, change how pydantic error are constructed, [#819](https://github.com/pydantic/pydantic/pull/819) by @samuelcolvin * Fix the error message arising when a `BaseModel`-type model field causes a `ValidationError` during parsing, [#820](https://github.com/pydantic/pydantic/pull/820) by @dmontagu * allow `getter_dict` on `Config`, modify `GetterDict` to be more like a `Mapping` object and thus easier to work with, [#821](https://github.com/pydantic/pydantic/pull/821) by @samuelcolvin * Only check `TypeVar` param on base `GenericModel` class, [#842](https://github.com/pydantic/pydantic/pull/842) by @zpencerq * rename `Model._schema_cache` -> `Model.__schema_cache__`, `Model._json_encoder` -> `Model.__json_encoder__`, `Model._custom_root_type` -> `Model.__custom_root_type__`, [#851](https://github.com/pydantic/pydantic/pull/851) by @samuelcolvin ## v0.32.2 (2019-08-17) (Docs are available [here](https://5d584fcca7c9b70007d1c997--pydantic-docs.netlify.com)) * fix `__post_init__` usage with dataclass inheritance, fix [#739](https://github.com/pydantic/pydantic/pull/739) by @samuelcolvin * fix required fields validation on GenericModels classes, [#742](https://github.com/pydantic/pydantic/pull/742) by @amitbl * fix defining custom `Schema` on `GenericModel` fields, [#754](https://github.com/pydantic/pydantic/pull/754) by @amitbl ## v0.32.1 (2019-08-08) * do not validate extra fields when `validate_assignment` is on, [#724](https://github.com/pydantic/pydantic/pull/724) by @YaraslauZhylko ## v0.32 (2019-08-06) * add model name to `ValidationError` error message, [#676](https://github.com/pydantic/pydantic/pull/676) by @dmontagu * **breaking change**: remove `__getattr__` and rename `__values__` to `__dict__` on `BaseModel`, deprecation warning on use `__values__` attr, attributes access speed increased up to 14 times, [#712](https://github.com/pydantic/pydantic/pull/712) by @Bobronium * support `ForwardRef` (without self-referencing annotations) in Python 3.6, [#706](https://github.com/pydantic/pydantic/pull/706) by @koxudaxi * implement `schema_extra` in `Config` sub-class, [#663](https://github.com/pydantic/pydantic/pull/663) by @tiangolo ## v0.31.1 (2019-07-31) * fix json generation for `EnumError`, [#697](https://github.com/pydantic/pydantic/pull/697) by @dmontagu * update numerous dependencies ## v0.31 (2019-07-24) * better support for floating point `multiple_of` values, [#652](https://github.com/pydantic/pydantic/pull/652) by @justindujardin * fix schema generation for `NewType` and `Literal`, [#649](https://github.com/pydantic/pydantic/pull/649) by @dmontagu * fix `alias_generator` and field config conflict, [#645](https://github.com/pydantic/pydantic/pull/645) by @gmetzker and [#658](https://github.com/pydantic/pydantic/pull/658) by @Bobronium * more detailed message for `EnumError`, [#673](https://github.com/pydantic/pydantic/pull/673) by @dmontagu * add advanced exclude support for `dict`, `json` and `copy`, [#648](https://github.com/pydantic/pydantic/pull/648) by @Bobronium * fix bug in `GenericModel` for models with concrete parameterized fields, [#672](https://github.com/pydantic/pydantic/pull/672) by @dmontagu * add documentation for `Literal` type, [#651](https://github.com/pydantic/pydantic/pull/651) by @dmontagu * add `Config.keep_untouched` for custom descriptors support, [#679](https://github.com/pydantic/pydantic/pull/679) by @Bobronium * use `inspect.cleandoc` internally to get model description, [#657](https://github.com/pydantic/pydantic/pull/657) by @tiangolo * add `Color` to schema generation, by @euri10 * add documentation for Literal type, [#651](https://github.com/pydantic/pydantic/pull/651) by @dmontagu ## v0.30.1 (2019-07-15) * fix so nested classes which inherit and change `__init__` are correctly processed while still allowing `self` as a parameter, [#644](https://github.com/pydantic/pydantic/pull/644) by @lnaden and @dgasmith ## v0.30 (2019-07-07) * enforce single quotes in code, [#612](https://github.com/pydantic/pydantic/pull/612) by @samuelcolvin * fix infinite recursion with dataclass inheritance and `__post_init__`, [#606](https://github.com/pydantic/pydantic/pull/606) by @Hanaasagi * fix default values for `GenericModel`, [#610](https://github.com/pydantic/pydantic/pull/610) by @dmontagu * clarify that self-referencing models require Python 3.7+, [#616](https://github.com/pydantic/pydantic/pull/616) by @vlcinsky * fix truncate for types, [#611](https://github.com/pydantic/pydantic/pull/611) by @dmontagu * add `alias_generator` support, [#622](https://github.com/pydantic/pydantic/pull/622) by @Bobronium * fix unparameterized generic type schema generation, [#625](https://github.com/pydantic/pydantic/pull/625) by @dmontagu * fix schema generation with multiple/circular references to the same model, [#621](https://github.com/pydantic/pydantic/pull/621) by @tiangolo and @wongpat * support custom root types, [#628](https://github.com/pydantic/pydantic/pull/628) by @koxudaxi * support `self` as a field name in `parse_obj`, [#632](https://github.com/pydantic/pydantic/pull/632) by @samuelcolvin ## v0.29 (2019-06-19) * support dataclasses.InitVar, [#592](https://github.com/pydantic/pydantic/pull/592) by @pfrederiks * Updated documentation to elucidate the usage of `Union` when defining multiple types under an attribute's annotation and showcase how the type-order can affect marshalling of provided values, [#594](https://github.com/pydantic/pydantic/pull/594) by @somada141 * add `conlist` type, [#583](https://github.com/pydantic/pydantic/pull/583) by @hmvp * add support for generics, [#595](https://github.com/pydantic/pydantic/pull/595) by @dmontagu ## v0.28 (2019-06-06) * fix support for JSON Schema generation when using models with circular references in Python 3.7, [#572](https://github.com/pydantic/pydantic/pull/572) by @tiangolo * support `__post_init_post_parse__` on dataclasses, [#567](https://github.com/pydantic/pydantic/pull/567) by @sevaho * allow dumping dataclasses to JSON, [#575](https://github.com/pydantic/pydantic/pull/575) by @samuelcolvin and @DanielOberg * ORM mode, [#562](https://github.com/pydantic/pydantic/pull/562) by @samuelcolvin * fix `pydantic.compiled` on ipython, [#573](https://github.com/pydantic/pydantic/pull/573) by @dmontagu and @samuelcolvin * add `StrictBool` type, [#579](https://github.com/pydantic/pydantic/pull/579) by @cazgp ## v0.27 (2019-05-30) * **breaking change** `_pydantic_post_init` to execute dataclass' original `__post_init__` before validation, [#560](https://github.com/pydantic/pydantic/pull/560) by @HeavenVolkoff * fix handling of generic types without specified parameters, [#550](https://github.com/pydantic/pydantic/pull/550) by @dmontagu * **breaking change** (maybe): this is the first release compiled with **cython**, see the docs and please submit an issue if you run into problems ## v0.27.0a1 (2019-05-26) * fix JSON Schema for `list`, `tuple`, and `set`, [#540](https://github.com/pydantic/pydantic/pull/540) by @tiangolo * compiling with cython, `manylinux` binaries, some other performance improvements, [#548](https://github.com/pydantic/pydantic/pull/548) by @samuelcolvin ## v0.26 (2019-05-22) * fix to schema generation for `IPvAnyAddress`, `IPvAnyInterface`, `IPvAnyNetwork` [#498](https://github.com/pydantic/pydantic/pull/498) by @pilosus * fix variable length tuples support, [#495](https://github.com/pydantic/pydantic/pull/495) by @pilosus * fix return type hint for `create_model`, [#526](https://github.com/pydantic/pydantic/pull/526) by @dmontagu * **Breaking Change:** fix `.dict(skip_keys=True)` skipping values set via alias (this involves changing `validate_model()` to always returns `Tuple[Dict[str, Any], Set[str], Optional[ValidationError]]`), [#517](https://github.com/pydantic/pydantic/pull/517) by @sommd * fix to schema generation for `IPv4Address`, `IPv6Address`, `IPv4Interface`, `IPv6Interface`, `IPv4Network`, `IPv6Network` [#532](https://github.com/pydantic/pydantic/pull/532) by @euri10 * add `Color` type, [#504](https://github.com/pydantic/pydantic/pull/504) by @pilosus and @samuelcolvin ## v0.25 (2019-05-05) * Improve documentation on self-referencing models and annotations, [#487](https://github.com/pydantic/pydantic/pull/487) by @theenglishway * fix `.dict()` with extra keys, [#490](https://github.com/pydantic/pydantic/pull/490) by @JaewonKim * support `const` keyword in `Schema`, [#434](https://github.com/pydantic/pydantic/pull/434) by @Sean1708 ## v0.24 (2019-04-23) * fix handling `ForwardRef` in sub-types, like `Union`, [#464](https://github.com/pydantic/pydantic/pull/464) by @tiangolo * fix secret serialization, [#465](https://github.com/pydantic/pydantic/pull/465) by @atheuz * Support custom validators for dataclasses, [#454](https://github.com/pydantic/pydantic/pull/454) by @primal100 * fix `parse_obj` to cope with dict-like objects, [#472](https://github.com/pydantic/pydantic/pull/472) by @samuelcolvin * fix to schema generation in nested dataclass-based models, [#474](https://github.com/pydantic/pydantic/pull/474) by @NoAnyLove * fix `json` for `Path`, `FilePath`, and `DirectoryPath` objects, [#473](https://github.com/pydantic/pydantic/pull/473) by @mikegoodspeed ## v0.23 (2019-04-04) * improve documentation for contributing section, [#441](https://github.com/pydantic/pydantic/pull/441) by @pilosus * improve README.rst to include essential information about the package, [#446](https://github.com/pydantic/pydantic/pull/446) by @pilosus * `IntEnum` support, [#444](https://github.com/pydantic/pydantic/pull/444) by @potykion * fix PyObject callable value, [#409](https://github.com/pydantic/pydantic/pull/409) by @pilosus * fix `black` deprecation warnings after update, [#451](https://github.com/pydantic/pydantic/pull/451) by @pilosus * fix `ForwardRef` collection bug, [#450](https://github.com/pydantic/pydantic/pull/450) by @tigerwings * Support specialized `ClassVars`, [#455](https://github.com/pydantic/pydantic/pull/455) by @tyrylu * fix JSON serialization for `ipaddress` types, [#333](https://github.com/pydantic/pydantic/pull/333) by @pilosus * add `SecretStr` and `SecretBytes` types, [#452](https://github.com/pydantic/pydantic/pull/452) by @atheuz ## v0.22 (2019-03-29) * add `IPv{4,6,Any}Network` and `IPv{4,6,Any}Interface` types from `ipaddress` stdlib, [#333](https://github.com/pydantic/pydantic/pull/333) by @pilosus * add docs for `datetime` types, [#386](https://github.com/pydantic/pydantic/pull/386) by @pilosus * fix to schema generation in dataclass-based models, [#408](https://github.com/pydantic/pydantic/pull/408) by @pilosus * fix path in nested models, [#437](https://github.com/pydantic/pydantic/pull/437) by @kataev * add `Sequence` support, [#304](https://github.com/pydantic/pydantic/pull/304) by @pilosus ## v0.21.0 (2019-03-15) * fix typo in `NoneIsNotAllowedError` message, [#414](https://github.com/pydantic/pydantic/pull/414) by @YaraslauZhylko * add `IPvAnyAddress`, `IPv4Address` and `IPv6Address` types, [#333](https://github.com/pydantic/pydantic/pull/333) by @pilosus ## v0.20.1 (2019-02-26) * fix type hints of `parse_obj` and similar methods, [#405](https://github.com/pydantic/pydantic/pull/405) by @erosennin * fix submodel validation, [#403](https://github.com/pydantic/pydantic/pull/403) by @samuelcolvin * correct type hints for `ValidationError.json`, [#406](https://github.com/pydantic/pydantic/pull/406) by @layday ## v0.20.0 (2019-02-18) * fix tests for Python 3.8, [#396](https://github.com/pydantic/pydantic/pull/396) by @samuelcolvin * Adds fields to the `dir` method for autocompletion in interactive sessions, [#398](https://github.com/pydantic/pydantic/pull/398) by @dgasmith * support `ForwardRef` (and therefore `from __future__ import annotations`) with dataclasses, [#397](https://github.com/pydantic/pydantic/pull/397) by @samuelcolvin ## v0.20.0a1 (2019-02-13) * **breaking change** (maybe): more sophisticated argument parsing for validators, any subset of `values`, `config` and `field` is now permitted, eg. `(cls, value, field)`, however the variadic key word argument ("`**kwargs`") **must** be called `kwargs`, [#388](https://github.com/pydantic/pydantic/pull/388) by @samuelcolvin * **breaking change**: Adds `skip_defaults` argument to `BaseModel.dict()` to allow skipping of fields that were not explicitly set, signature of `Model.construct()` changed, [#389](https://github.com/pydantic/pydantic/pull/389) by @dgasmith * add `py.typed` marker file for PEP-561 support, [#391](https://github.com/pydantic/pydantic/pull/391) by @je-l * Fix `extra` behaviour for multiple inheritance/mix-ins, [#394](https://github.com/pydantic/pydantic/pull/394) by @YaraslauZhylko ## v0.19.0 (2019-02-04) * Support `Callable` type hint, fix [#279](https://github.com/pydantic/pydantic/pull/279) by @proofit404 * Fix schema for fields with `validator` decorator, fix [#375](https://github.com/pydantic/pydantic/pull/375) by @tiangolo * Add `multiple_of` constraint to `ConstrainedDecimal`, `ConstrainedFloat`, `ConstrainedInt` and their related types `condecimal`, `confloat`, and `conint` [#371](https://github.com/pydantic/pydantic/pull/371), thanks @StephenBrown2 * Deprecated `ignore_extra` and `allow_extra` Config fields in favor of `extra`, [#352](https://github.com/pydantic/pydantic/pull/352) by @liiight * Add type annotations to all functions, test fully with mypy, [#373](https://github.com/pydantic/pydantic/pull/373) by @samuelcolvin * fix for 'missing' error with `validate_all` or `validate_always`, [#381](https://github.com/pydantic/pydantic/pull/381) by @samuelcolvin * Change the second/millisecond watershed for date/datetime parsing to `2e10`, [#385](https://github.com/pydantic/pydantic/pull/385) by @samuelcolvin ## v0.18.2 (2019-01-22) * Fix to schema generation with `Optional` fields, fix [#361](https://github.com/pydantic/pydantic/pull/361) by @samuelcolvin ## v0.18.1 (2019-01-17) * add `ConstrainedBytes` and `conbytes` types, [#315](https://github.com/pydantic/pydantic/pull/315) @Gr1N * adding `MANIFEST.in` to include license in package `.tar.gz`, [#358](https://github.com/pydantic/pydantic/pull/358) by @samuelcolvin ## v0.18.0 (2019-01-13) * **breaking change**: don't call validators on keys of dictionaries, [#254](https://github.com/pydantic/pydantic/pull/254) by @samuelcolvin * Fix validators with `always=True` when the default is `None` or the type is optional, also prevent `whole` validators being called for sub-fields, fix [#132](https://github.com/pydantic/pydantic/pull/132) by @samuelcolvin * improve documentation for settings priority and allow it to be easily changed, [#343](https://github.com/pydantic/pydantic/pull/343) by @samuelcolvin * fix `ignore_extra=False` and `allow_population_by_alias=True`, fix [#257](https://github.com/pydantic/pydantic/pull/257) by @samuelcolvin * **breaking change**: Set `BaseConfig` attributes `min_anystr_length` and `max_anystr_length` to `None` by default, fix [#349](https://github.com/pydantic/pydantic/pull/349) in [#350](https://github.com/pydantic/pydantic/pull/350) by @tiangolo * add support for postponed annotations, [#348](https://github.com/pydantic/pydantic/pull/348) by @samuelcolvin ## v0.17.0 (2018-12-27) * fix schema for `timedelta` as number, [#325](https://github.com/pydantic/pydantic/pull/325) by @tiangolo * prevent validators being called repeatedly after inheritance, [#327](https://github.com/pydantic/pydantic/pull/327) by @samuelcolvin * prevent duplicate validator check in ipython, fix [#312](https://github.com/pydantic/pydantic/pull/312) by @samuelcolvin * add "Using Pydantic" section to docs, [#323](https://github.com/pydantic/pydantic/pull/323) by @tiangolo & [#326](https://github.com/pydantic/pydantic/pull/326) by @samuelcolvin * fix schema generation for fields annotated as `: dict`, `: list`, `: tuple` and `: set`, [#330](https://github.com/pydantic/pydantic/pull/330) & [#335](https://github.com/pydantic/pydantic/pull/335) by @nkonin * add support for constrained strings as dict keys in schema, [#332](https://github.com/pydantic/pydantic/pull/332) by @tiangolo * support for passing Config class in dataclasses decorator, [#276](https://github.com/pydantic/pydantic/pull/276) by @jarekkar (**breaking change**: this supersedes the `validate_assignment` argument with `config`) * support for nested dataclasses, [#334](https://github.com/pydantic/pydantic/pull/334) by @samuelcolvin * better errors when getting an `ImportError` with `PyObject`, [#309](https://github.com/pydantic/pydantic/pull/309) by @samuelcolvin * rename `get_validators` to `__get_validators__`, deprecation warning on use of old name, [#338](https://github.com/pydantic/pydantic/pull/338) by @samuelcolvin * support `ClassVar` by excluding such attributes from fields, [#184](https://github.com/pydantic/pydantic/pull/184) by @samuelcolvin ## v0.16.1 (2018-12-10) * fix `create_model` to correctly use the passed `__config__`, [#320](https://github.com/pydantic/pydantic/pull/320) by @hugoduncan ## v0.16.0 (2018-12-03) * **breaking change**: refactor schema generation to be compatible with JSON Schema and OpenAPI specs, [#308](https://github.com/pydantic/pydantic/pull/308) by @tiangolo * add `schema` to `schema` module to generate top-level schemas from base models, [#308](https://github.com/pydantic/pydantic/pull/308) by @tiangolo * add additional fields to `Schema` class to declare validation for `str` and numeric values, [#311](https://github.com/pydantic/pydantic/pull/311) by @tiangolo * rename `_schema` to `schema` on fields, [#318](https://github.com/pydantic/pydantic/pull/318) by @samuelcolvin * add `case_insensitive` option to `BaseSettings` `Config`, [#277](https://github.com/pydantic/pydantic/pull/277) by @jasonkuhrt ## v0.15.0 (2018-11-18) * move codebase to use black, [#287](https://github.com/pydantic/pydantic/pull/287) by @samuelcolvin * fix alias use in settings, [#286](https://github.com/pydantic/pydantic/pull/286) by @jasonkuhrt and @samuelcolvin * fix datetime parsing in `parse_date`, [#298](https://github.com/pydantic/pydantic/pull/298) by @samuelcolvin * allow dataclass inheritance, fix [#293](https://github.com/pydantic/pydantic/pull/293) by @samuelcolvin * fix `PyObject = None`, fix [#305](https://github.com/pydantic/pydantic/pull/305) by @samuelcolvin * allow `Pattern` type, fix [#303](https://github.com/pydantic/pydantic/pull/303) by @samuelcolvin ## v0.14.0 (2018-10-02) * dataclasses decorator, [#269](https://github.com/pydantic/pydantic/pull/269) by @Gaunt and @samuelcolvin ## v0.13.1 (2018-09-21) * fix issue where int_validator doesn't cast a `bool` to an `int` [#264](https://github.com/pydantic/pydantic/pull/264) by @nphyatt * add deep copy support for `BaseModel.copy()` [#249](https://github.com/pydantic/pydantic/pull/249), @gangefors ## v0.13.0 (2018-08-25) * raise an exception if a field's name shadows an existing `BaseModel` attribute [#242](https://github.com/pydantic/pydantic/pull/242) * add `UrlStr` and `urlstr` types [#236](https://github.com/pydantic/pydantic/pull/236) * timedelta json encoding ISO8601 and total seconds, custom json encoders [#247](https://github.com/pydantic/pydantic/pull/247), by @cfkanesan and @samuelcolvin * allow `timedelta` objects as values for properties of type `timedelta` (matches `datetime` etc. behavior) [#247](https://github.com/pydantic/pydantic/pull/247) ## v0.12.1 (2018-07-31) * fix schema generation for fields defined using `typing.Any` [#237](https://github.com/pydantic/pydantic/pull/237) ## v0.12.0 (2018-07-31) * add `by_alias` argument in `.dict()` and `.json()` model methods [#205](https://github.com/pydantic/pydantic/pull/205) * add Json type support [#214](https://github.com/pydantic/pydantic/pull/214) * support tuples [#227](https://github.com/pydantic/pydantic/pull/227) * major improvements and changes to schema [#213](https://github.com/pydantic/pydantic/pull/213) ## v0.11.2 (2018-07-05) * add `NewType` support [#115](https://github.com/pydantic/pydantic/pull/115) * fix `list`, `set` & `tuple` validation [#225](https://github.com/pydantic/pydantic/pull/225) * separate out `validate_model` method, allow errors to be returned along with valid values [#221](https://github.com/pydantic/pydantic/pull/221) ## v0.11.1 (2018-07-02) * support Python 3.7 [#216](https://github.com/pydantic/pydantic/pull/216), thanks @layday * Allow arbitrary types in model [#209](https://github.com/pydantic/pydantic/pull/209), thanks @oldPadavan ## v0.11.0 (2018-06-28) * make `list`, `tuple` and `set` types stricter [#86](https://github.com/pydantic/pydantic/pull/86) * **breaking change**: remove msgpack parsing [#201](https://github.com/pydantic/pydantic/pull/201) * add `FilePath` and `DirectoryPath` types [#10](https://github.com/pydantic/pydantic/pull/10) * model schema generation [#190](https://github.com/pydantic/pydantic/pull/190) * JSON serialization of models and schemas [#133](https://github.com/pydantic/pydantic/pull/133) ## v0.10.0 (2018-06-11) * add `Config.allow_population_by_alias` [#160](https://github.com/pydantic/pydantic/pull/160), thanks @bendemaree * **breaking change**: new errors format [#179](https://github.com/pydantic/pydantic/pull/179), thanks @Gr1N * **breaking change**: removed `Config.min_number_size` and `Config.max_number_size` [#183](https://github.com/pydantic/pydantic/pull/183), thanks @Gr1N * **breaking change**: correct behaviour of `lt` and `gt` arguments to `conint` etc. [#188](https://github.com/pydantic/pydantic/pull/188) for the old behaviour use `le` and `ge` [#194](https://github.com/pydantic/pydantic/pull/194), thanks @jaheba * added error context and ability to redefine error message templates using `Config.error_msg_templates` [#183](https://github.com/pydantic/pydantic/pull/183), thanks @Gr1N * fix typo in validator exception [#150](https://github.com/pydantic/pydantic/pull/150) * copy defaults to model values, so different models don't share objects [#154](https://github.com/pydantic/pydantic/pull/154) ## v0.9.1 (2018-05-10) * allow custom `get_field_config` on config classes [#159](https://github.com/pydantic/pydantic/pull/159) * add `UUID1`, `UUID3`, `UUID4` and `UUID5` types [#167](https://github.com/pydantic/pydantic/pull/167), thanks @Gr1N * modify some inconsistent docstrings and annotations [#173](https://github.com/pydantic/pydantic/pull/173), thanks @YannLuo * fix type annotations for exotic types [#171](https://github.com/pydantic/pydantic/pull/171), thanks @Gr1N * Reuse type validators in exotic types [#171](https://github.com/pydantic/pydantic/pull/171) * scheduled monthly requirements updates [#168](https://github.com/pydantic/pydantic/pull/168) * add `Decimal`, `ConstrainedDecimal` and `condecimal` types [#170](https://github.com/pydantic/pydantic/pull/170), thanks @Gr1N ## v0.9.0 (2018-04-28) * tweak email-validator import error message [#145](https://github.com/pydantic/pydantic/pull/145) * fix parse error of `parse_date()` and `parse_datetime()` when input is 0 [#144](https://github.com/pydantic/pydantic/pull/144), thanks @YannLuo * add `Config.anystr_strip_whitespace` and `strip_whitespace` kwarg to `constr`, by default values is `False` [#163](https://github.com/pydantic/pydantic/pull/163), thanks @Gr1N * add `ConstrainedFloat`, `confloat`, `PositiveFloat` and `NegativeFloat` types [#166](https://github.com/pydantic/pydantic/pull/166), thanks @Gr1N ## v0.8.0 (2018-03-25) * fix type annotation for `inherit_config` [#139](https://github.com/pydantic/pydantic/pull/139) * **breaking change**: check for invalid field names in validators [#140](https://github.com/pydantic/pydantic/pull/140) * validate attributes of parent models [#141](https://github.com/pydantic/pydantic/pull/141) * **breaking change**: email validation now uses [email-validator](https://github.com/JoshData/python-email-validator) [#142](https://github.com/pydantic/pydantic/pull/142) ## v0.7.1 (2018-02-07) * fix bug with `create_model` modifying the base class ## v0.7.0 (2018-02-06) * added compatibility with abstract base classes (ABCs) [#123](https://github.com/pydantic/pydantic/pull/123) * add `create_model` method [#113](https://github.com/pydantic/pydantic/pull/113) [#125](https://github.com/pydantic/pydantic/pull/125) * **breaking change**: rename `.config` to `.__config__` on a model * **breaking change**: remove deprecated `.values()` on a model, use `.dict()` instead * remove use of `OrderedDict` and use simple dict [#126](https://github.com/pydantic/pydantic/pull/126) * add `Config.use_enum_values` [#127](https://github.com/pydantic/pydantic/pull/127) * add wildcard validators of the form `@validate('*')` [#128](https://github.com/pydantic/pydantic/pull/128) ## v0.6.4 (2018-02-01) * allow Python date and times objects [#122](https://github.com/pydantic/pydantic/pull/122) ## v0.6.3 (2017-11-26) * fix direct install without `README.rst` present ## v0.6.2 (2017-11-13) * errors for invalid validator use * safer check for complex models in `Settings` ## v0.6.1 (2017-11-08) * prevent duplicate validators, [#101](https://github.com/pydantic/pydantic/pull/101) * add `always` kwarg to validators, [#102](https://github.com/pydantic/pydantic/pull/102) ## v0.6.0 (2017-11-07) * assignment validation [#94](https://github.com/pydantic/pydantic/pull/94), thanks petroswork! * JSON in environment variables for complex types, [#96](https://github.com/pydantic/pydantic/pull/96) * add `validator` decorators for complex validation, [#97](https://github.com/pydantic/pydantic/pull/97) * depreciate `values(...)` and replace with `.dict(...)`, [#99](https://github.com/pydantic/pydantic/pull/99) ## v0.5.0 (2017-10-23) * add `UUID` validation [#89](https://github.com/pydantic/pydantic/pull/89) * remove `index` and `track` from error object (json) if they're null [#90](https://github.com/pydantic/pydantic/pull/90) * improve the error text when a list is provided rather than a dict [#90](https://github.com/pydantic/pydantic/pull/90) * add benchmarks table to docs [#91](https://github.com/pydantic/pydantic/pull/91) ## v0.4.0 (2017-07-08) * show length in string validation error * fix aliases in config during inheritance [#55](https://github.com/pydantic/pydantic/pull/55) * simplify error display * use unicode ellipsis in `truncate` * add `parse_obj`, `parse_raw` and `parse_file` helper functions [#58](https://github.com/pydantic/pydantic/pull/58) * switch annotation only fields to come first in fields list not last ## v0.3.0 (2017-06-21) * immutable models via `config.allow_mutation = False`, associated cleanup and performance improvement [#44](https://github.com/pydantic/pydantic/pull/44) * immutable helper methods `construct()` and `copy()` [#53](https://github.com/pydantic/pydantic/pull/53) * allow pickling of models [#53](https://github.com/pydantic/pydantic/pull/53) * `setattr` is removed as `__setattr__` is now intelligent [#44](https://github.com/pydantic/pydantic/pull/44) * `raise_exception` removed, Models now always raise exceptions [#44](https://github.com/pydantic/pydantic/pull/44) * instance method validators removed * django-restful-framework benchmarks added [#47](https://github.com/pydantic/pydantic/pull/47) * fix inheritance bug [#49](https://github.com/pydantic/pydantic/pull/49) * make str type stricter so list, dict etc are not coerced to strings. [#52](https://github.com/pydantic/pydantic/pull/52) * add `StrictStr` which only always strings as input [#52](https://github.com/pydantic/pydantic/pull/52) ## v0.2.1 (2017-06-07) * pypi and travis together messed up the deploy of `v0.2` this should fix it ## v0.2.0 (2017-06-07) * **breaking change**: `values()` on a model is now a method not a property, takes `include` and `exclude` arguments * allow annotation only fields to support mypy * add pretty `to_string(pretty=True)` method for models ## v0.1.0 (2017-06-03) * add docs * add history pydantic-pydantic-ba0aa01/LICENSE000066400000000000000000000021511517143232300166120ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2017 to present Pydantic Services Inc. and individual contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. pydantic-pydantic-ba0aa01/Makefile000066400000000000000000000117641517143232300172570ustar00rootroot00000000000000.DEFAULT_GOAL := all sources = pydantic tests docs/plugins release pydantic-core/python pydantic-core/tests pydantic-core/wasm-preview/run_tests.py NUM_THREADS?=1 .PHONY: .uv ## Check that uv is installed .uv: @uv -V || echo 'Please install uv: https://docs.astral.sh/uv/getting-started/installation/' .PHONY: .pre-commit ## Check that pre-commit is installed .pre-commit: .uv @uv run pre-commit -V || uv pip install pre-commit .PHONY: install ## Install the package, dependencies, and pre-commit for local development install: .uv uv sync --frozen --all-groups --all-packages --all-extras uv pip install pre-commit uv run pre-commit install --install-hooks .PHONY: rebuild-lockfiles ## Rebuild lockfiles from scratch, updating all dependencies rebuild-lockfiles: .uv uv lock --upgrade .PHONY: .rust # Check that Rust is installed .rust: @rustup --version || echo 'Please install Rust: https://rust-lang.org/tools/install/' .PHONY: format ## Auto-format python source files format: .uv .rust uv run ruff check --fix $(sources) uv run ruff format $(sources) cargo fmt --manifest-path pydantic-core/Cargo.toml .PHONY: lint-python ## Lint python source files lint-python: .uv uv run ruff check $(sources) uv run ruff format --check $(sources) .PHONY: lint-rust ## Lint Rust source files lint-rust: $(MAKE) -C pydantic-core lint-rust .PHONY: lint ## Lint all source files lint: lint-python lint-rust .PHONY: codespell ## Use Codespell to do spellchecking codespell: .pre-commit uv run pre-commit run codespell --all-files .PHONY: typecheck ## Perform type-checking typecheck: .pre-commit uv run pre-commit run typecheck --all-files .PHONY: test-mypy ## Run the mypy integration tests test-mypy: .uv uv run coverage run -m pytest tests/mypy --test-mypy .PHONY: test-mypy-update ## Update the mypy integration tests for the current mypy version test-mypy-update: .uv uv run coverage run -m pytest tests/mypy --test-mypy --update-mypy .PHONY: test-typechecking-pyright ## Typechecking integration tests (Pyright) test-typechecking-pyright: .uv uv run bash -c 'cd tests/typechecking && pyright --version && pyright -p pyproject.toml' .PHONY: test-typechecking-mypy ## Typechecking integration tests (Mypy). Not to be confused with `test-mypy`. test-typechecking-mypy: .uv uv run bash -c 'cd tests/typechecking && mypy --version && mypy --cache-dir=/dev/null --config-file pyproject.toml .' .PHONY: test-typechecking-pyrefly ## Typechecking integration tests (Pyrefly). test-typechecking-pyrefly: .uv uv run bash -c 'cd tests/typechecking && pyrefly --version && pyrefly check' .PHONY: test ## Run all tests, skipping the type-checker integration tests test: .uv uv run coverage run -m pytest --durations=10 --parallel-threads $(NUM_THREADS) .PHONY: benchmark ## Run all benchmarks benchmark: .uv uv run coverage run -m pytest --durations=10 --benchmark-enable tests/benchmarks .PHONY: testcov ## Run tests and generate a coverage report, skipping the type-checker integration tests testcov: test @echo "building coverage html" @uv run coverage html @echo "building coverage lcov" @uv run coverage lcov .PHONY: test-examples ## Run only the tests from the documentation test-examples: .uv @echo "running examples" @find docs/examples -type f -name '*.py' | xargs -I'{}' sh -c 'uv run python {} >/dev/null 2>&1 || (echo "{} failed")' .PHONY: test-pydantic-settings ## Run the pydantic-settings tests with this version of pydantic test-pydantic-settings: .uv git clone https://github.com/pydantic/pydantic-settings.git --single-branch bash ./tests/test_pydantic_settings.sh .PHONY: test-pydantic-extra-types ## Run the pydantic-extra-types tests with this version of pydantic test-pydantic-extra-types: .uv git clone https://github.com/pydantic/pydantic-extra-types.git --single-branch bash ./tests/test_pydantic_extra_types.sh .PHONY: test-no-docs # Run all tests except the docs tests test-no-docs: .uv uv run pytest tests --ignore=tests/test_docs.py .PHONY: all ## Run the standard set of checks performed in CI all: lint typecheck codespell testcov .PHONY: clean ## Clear local caches and build artifacts clean: rm -rf `find . -name __pycache__` rm -f `find . -type f -name '*.py[co]'` rm -f `find . -type f -name '*~'` rm -f `find . -type f -name '.*~'` rm -rf .cache rm -rf .pytest_cache rm -rf .ruff_cache rm -rf htmlcov rm -rf *.egg-info rm -f .coverage rm -f .coverage.* rm -rf build rm -rf dist rm -rf site rm -rf docs/_build rm -rf docs/.changelog.md docs/.version.md docs/.tmp_schema_mappings.html rm -rf fastapi/test.db rm -rf coverage.xml .PHONY: docs ## Generate the docs docs: uv run mkdocs build --strict .PHONY: docs-serve docs-serve: ## Build and serve the documentation, for local preview uv run mkdocs serve --strict .PHONY: help ## Display this message help: @grep -E \ '^.PHONY: .*?## .*$$' $(MAKEFILE_LIST) | \ sort | \ awk 'BEGIN {FS = ".PHONY: |## "}; {printf "\033[36m%-19s\033[0m %s\n", $$2, $$3}' .PHONY: update-v1 ## Update V1 namespace update-v1: uv run ./update_v1.sh pydantic-pydantic-ba0aa01/README.md000066400000000000000000000063401517143232300170700ustar00rootroot00000000000000# Pydantic Validation [![CI](https://img.shields.io/github/actions/workflow/status/pydantic/pydantic/ci.yml?branch=main&logo=github&label=CI)](https://github.com/pydantic/pydantic/actions?query=event%3Apush+branch%3Amain+workflow%3ACI) [![Coverage](https://coverage-badge.samuelcolvin.workers.dev/pydantic/pydantic.svg)](https://coverage-badge.samuelcolvin.workers.dev/redirect/pydantic/pydantic) [![pypi](https://img.shields.io/pypi/v/pydantic.svg)](https://pypi.python.org/pypi/pydantic) [![CondaForge](https://img.shields.io/conda/v/conda-forge/pydantic.svg)](https://anaconda.org/conda-forge/pydantic) [![downloads](https://static.pepy.tech/badge/pydantic/month)](https://pepy.tech/project/pydantic) [![versions](https://img.shields.io/pypi/pyversions/pydantic.svg)](https://github.com/pydantic/pydantic) [![license](https://img.shields.io/github/license/pydantic/pydantic.svg)](https://github.com/pydantic/pydantic/blob/main/LICENSE) [![Pydantic v2](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/pydantic/pydantic/main/docs/badge/v2.json)](https://docs.pydantic.dev/latest/contributing/#badges) [![llms.txt](https://img.shields.io/badge/llms.txt-green)](https://docs.pydantic.dev/latest/llms.txt) Data validation using Python type hints. Fast and extensible, Pydantic plays nicely with your linters/IDE/brain. Define how data should be in pure, canonical Python 3.9+; validate it with Pydantic. ## Pydantic Logfire :fire: We've launched Pydantic Logfire to help you monitor your applications. [Learn more](https://pydantic.dev/logfire/?utm_source=pydantic_validation) ## Pydantic V1.10 vs. V2 Pydantic V2 is a ground-up rewrite that offers many new features, performance improvements, and some breaking changes compared to Pydantic V1. If you're using Pydantic V1 you may want to look at the [pydantic V1.10 Documentation](https://docs.pydantic.dev/) or, [`1.10.X-fixes` git branch](https://github.com/pydantic/pydantic/tree/1.10.X-fixes). Pydantic V2 also ships with the latest version of Pydantic V1 built in so that you can incrementally upgrade your code base and projects: `from pydantic import v1 as pydantic_v1`. ## Help See [documentation](https://docs.pydantic.dev/) for more details. ## Installation Install using `pip install -U pydantic` or `conda install pydantic -c conda-forge`. For more installation options to make Pydantic even faster, see the [Install](https://docs.pydantic.dev/install/) section in the documentation. ## A Simple Example ```python from datetime import datetime from typing import Optional from pydantic import BaseModel class User(BaseModel): id: int name: str = 'John Doe' signup_ts: Optional[datetime] = None friends: list[int] = [] external_data = {'id': '123', 'signup_ts': '2017-06-01 12:22', 'friends': [1, '2', b'3']} user = User(**external_data) print(user) #> User id=123 name='John Doe' signup_ts=datetime.datetime(2017, 6, 1, 12, 22) friends=[1, 2, 3] print(user.id) #> 123 ``` ## Contributing For guidance on setting up a development environment and how to make a contribution to Pydantic, see [Contributing to Pydantic](https://docs.pydantic.dev/contributing/). ## Reporting a Security Vulnerability See our [security policy](https://github.com/pydantic/pydantic/security/policy). pydantic-pydantic-ba0aa01/build-docs.sh000077500000000000000000000021761517143232300202000ustar00rootroot00000000000000#!/usr/bin/env bash # This script is used to build the documentation on CloudFlare Pages, this is just used for build previews # A different script with the same name exists on the `docs-site` branch (where pre-built docs live). set -e set -x # Install Rust curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y source $HOME/.cargo/env # Install uv curl -LsSf https://astral.sh/uv/install.sh | sh uv sync --python 3.12 --group docs --frozen uv run --no-sync python -c 'import docs.plugins.main' # Adding local symlinks gets nice source locations like # pydantic_core/core_schema.py # instead of # pydantic-core/python/pydantic_core/core_schema.py # See also: mkdocs.yml:mkdocstrings:handlers:python:paths: [.]: ln -s pydantic-core/python/pydantic_core pydantic_core ln -s .venv/lib/python*/site-packages/pydantic_settings pydantic_settings ln -s .venv/lib/python*/site-packages/pydantic_extra_types pydantic_extra_types # Put these at the front of PYTHONPATH (otherwise, symlinked # entries will still have "Source code in .venv/lib/.../*.py ": PYTHONPATH="$PWD${PYTHONPATH:+:${PYTHONPATH}}" uv run --no-sync mkdocs build pydantic-pydantic-ba0aa01/docs/000077500000000000000000000000001517143232300165365ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/docs/api/000077500000000000000000000000001517143232300173075ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/docs/api/aliases.md000066400000000000000000000000251517143232300212470ustar00rootroot00000000000000::: pydantic.aliases pydantic-pydantic-ba0aa01/docs/api/annotated_handlers.md000066400000000000000000000000401517143232300234600ustar00rootroot00000000000000::: pydantic.annotated_handlers pydantic-pydantic-ba0aa01/docs/api/base_model.md000066400000000000000000000016421517143232300217260ustar00rootroot00000000000000Pydantic models are simply classes which inherit from `BaseModel` and define fields as annotated attributes. ::: pydantic.BaseModel options: show_root_heading: true merge_init_into_class: false group_by_category: false # explicit members list so we can set order and include `__init__` easily members: - __init__ - model_config - model_fields - model_computed_fields - __pydantic_core_schema__ - model_extra - model_fields_set - model_construct - model_copy - model_dump - model_dump_json - model_json_schema - model_parametrized_name - model_post_init - model_rebuild - model_validate - model_validate_json - model_validate_strings ::: pydantic.create_model options: show_root_heading: true pydantic-pydantic-ba0aa01/docs/api/config.md000066400000000000000000000003571517143232300211030ustar00rootroot00000000000000::: pydantic.config options: group_by_category: false members: - ConfigDict - with_config - ExtraValues - BaseConfig ::: pydantic.alias_generators options: show_root_heading: true pydantic-pydantic-ba0aa01/docs/api/dataclasses.md000066400000000000000000000000311517143232300221120ustar00rootroot00000000000000::: pydantic.dataclasses pydantic-pydantic-ba0aa01/docs/api/errors.md000066400000000000000000000000241517143232300211410ustar00rootroot00000000000000::: pydantic.errors pydantic-pydantic-ba0aa01/docs/api/experimental.md000066400000000000000000000004111517143232300223220ustar00rootroot00000000000000# Experimental API ## Pipeline API ::: pydantic.experimental.pipeline options: members: - _Pipeline ## Arguments schema API ::: pydantic.experimental.arguments_schema options: members: - generate_arguments_schema pydantic-pydantic-ba0aa01/docs/api/fields.md000066400000000000000000000006561517143232300211060ustar00rootroot00000000000000::: pydantic.fields options: group_by_category: false members: - Field - FieldInfo - PrivateAttr - ModelPrivateAttr - computed_field - ComputedFieldInfo filters: - "!^from_field$" - "!^from_annotation$" - "!^from_annotated_attribute$" - "!^merge_field_infos$" - "!^rebuild_annotation$" - "!^apply_typevars_map$" pydantic-pydantic-ba0aa01/docs/api/functional_serializers.md000066400000000000000000000000441517143232300244050ustar00rootroot00000000000000::: pydantic.functional_serializers pydantic-pydantic-ba0aa01/docs/api/functional_validators.md000066400000000000000000000000431517143232300242200ustar00rootroot00000000000000::: pydantic.functional_validators pydantic-pydantic-ba0aa01/docs/api/json_schema.md000066400000000000000000000000311517143232300221140ustar00rootroot00000000000000::: pydantic.json_schema pydantic-pydantic-ba0aa01/docs/api/networks.md000066400000000000000000000000261517143232300215030ustar00rootroot00000000000000::: pydantic.networks pydantic-pydantic-ba0aa01/docs/api/pydantic_core.md000066400000000000000000000013021517143232300224500ustar00rootroot00000000000000::: pydantic_core options: allow_inspection: false show_source: false members: - SchemaValidator - SchemaSerializer - ValidationError - ErrorDetails - InitErrorDetails - SchemaError - PydanticCustomError - PydanticKnownError - PydanticOmit - PydanticUseDefault - PydanticSerializationError - PydanticSerializationUnexpectedValue - Url - MultiHostUrl - MultiHostHost - ArgsKwargs - Some - TzInfo - to_json - from_json - to_jsonable_python - list_all_errors - ErrorTypeInfo - __version__ pydantic-pydantic-ba0aa01/docs/api/pydantic_core_schema.md000066400000000000000000000000361517143232300237730ustar00rootroot00000000000000::: pydantic_core.core_schema pydantic-pydantic-ba0aa01/docs/api/pydantic_extra_types_color.md000066400000000000000000000000371517143232300252710ustar00rootroot00000000000000::: pydantic_extra_types.color pydantic-pydantic-ba0aa01/docs/api/pydantic_extra_types_coordinate.md000066400000000000000000000000441517143232300263000ustar00rootroot00000000000000::: pydantic_extra_types.coordinate pydantic-pydantic-ba0aa01/docs/api/pydantic_extra_types_country.md000066400000000000000000000000411517143232300256510ustar00rootroot00000000000000::: pydantic_extra_types.country pydantic-pydantic-ba0aa01/docs/api/pydantic_extra_types_currency_code.md000066400000000000000000000000471517143232300270000ustar00rootroot00000000000000::: pydantic_extra_types.currency_code pydantic-pydantic-ba0aa01/docs/api/pydantic_extra_types_isbn.md000066400000000000000000000000361517143232300251050ustar00rootroot00000000000000::: pydantic_extra_types.isbn pydantic-pydantic-ba0aa01/docs/api/pydantic_extra_types_language_code.md000066400000000000000000000000471517143232300267310ustar00rootroot00000000000000::: pydantic_extra_types.language_code pydantic-pydantic-ba0aa01/docs/api/pydantic_extra_types_mac_address.md000066400000000000000000000000451517143232300264170ustar00rootroot00000000000000::: pydantic_extra_types.mac_address pydantic-pydantic-ba0aa01/docs/api/pydantic_extra_types_payment.md000066400000000000000000000000411517143232300256230ustar00rootroot00000000000000::: pydantic_extra_types.payment pydantic-pydantic-ba0aa01/docs/api/pydantic_extra_types_pendulum_dt.md000066400000000000000000000000451517143232300264720ustar00rootroot00000000000000::: pydantic_extra_types.pendulum_dt pydantic-pydantic-ba0aa01/docs/api/pydantic_extra_types_phone_numbers.md000066400000000000000000000000471517143232300270200ustar00rootroot00000000000000::: pydantic_extra_types.phone_numbers pydantic-pydantic-ba0aa01/docs/api/pydantic_extra_types_routing_numbers.md000066400000000000000000000000501517143232300273700ustar00rootroot00000000000000::: pydantic_extra_types.routing_number pydantic-pydantic-ba0aa01/docs/api/pydantic_extra_types_script_code.md000066400000000000000000000000451517143232300264500ustar00rootroot00000000000000::: pydantic_extra_types.script_code pydantic-pydantic-ba0aa01/docs/api/pydantic_extra_types_semantic_version.md000066400000000000000000000000521517143232300275200ustar00rootroot00000000000000::: pydantic_extra_types.semantic_version pydantic-pydantic-ba0aa01/docs/api/pydantic_extra_types_timezone_name.md000066400000000000000000000000471517143232300270060ustar00rootroot00000000000000::: pydantic_extra_types.timezone_name pydantic-pydantic-ba0aa01/docs/api/pydantic_extra_types_ulid.md000066400000000000000000000000361517143232300251070ustar00rootroot00000000000000::: pydantic_extra_types.ulid pydantic-pydantic-ba0aa01/docs/api/pydantic_settings.md000066400000000000000000000000261517143232300233620ustar00rootroot00000000000000::: pydantic_settings pydantic-pydantic-ba0aa01/docs/api/root_model.md000066400000000000000000000000301517143232300217650ustar00rootroot00000000000000::: pydantic.root_model pydantic-pydantic-ba0aa01/docs/api/standard_library_types.md000066400000000000000000001706401517143232300244110ustar00rootroot00000000000000--- description: Support for common types from the Python standard library. --- This section enumerates the supported built-in and standard library types: the allowed values, the possible constraints, and whether strictness can be configured. See also the [conversion table](../concepts/conversion_table.md) for a summary of the allowed values for each type. !!! note Unless specified otherwise, values are serialized as-is, in both Python and JSON modes. ## Booleans Built-in type: [`bool`][]

Validation

* A valid [`bool`][] instance, i.e. `True` or `False`. * The integers `0` or `1`. * A string, which when converted to lowercase is one of `'0'`, `'off'`, `'f'`, `'false'`, `'n'`, `'no'`, `'1'`, `'on'` `'t'`, `'true'`, `'y'`, `'yes'`. * [`bytes`][] objects that are valid per the previous rule when decoded to a string.

Strictness

In [strict mode](../concepts/strict_mode.md), only boolean values are valid. Pydantic provides the [`StrictBool`][pydantic.types.StrictBool] type as a convenience to [using the `Strict()` metadata class](../concepts/strict_mode.md#using-the-strict-metadata-class).

Example

```python from pydantic import BaseModel, ValidationError class BooleanModel(BaseModel): bool_value: bool print(BooleanModel(bool_value=False)) #> bool_value=False print(BooleanModel(bool_value='False')) #> bool_value=False print(BooleanModel(bool_value=1)) #> bool_value=True try: BooleanModel(bool_value=[]) except ValidationError as e: print(str(e)) """ 1 validation error for BooleanModel bool_value Input should be a valid boolean [type=bool_type, input_value=[], input_type=list] """ ``` ## Strings Built-in type: [`str`][]

Validation

* Strings are accepted as-is. * [`bytes`][] and [`bytearray`][] are decoded to UTF-8 strings. * [Enums][enum] are converted using the [`value`][enum.Enum.value] attribute, by calling [`str()`][str] on it. * If [`coerce_numbers_to_str`][pydantic.ConfigDict.coerce_numbers_to_str] is set, any number type ([`int`][], [`float`][] and [`Decimal`][decimal.Decimal]) will be coerced to a string and accepted as-is.

Constraints

Strings support the following constraints: | Constraint | Description | JSON Schema | | ------------------ | ------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | `pattern` | A regex pattern that the string must match | [`pattern`](https://json-schema.org/understanding-json-schema/reference/string#regexp) keyword (see [note](#pattern-constraint-note) below). | | `min_length` | The minimum length of the string | [`minLength`](https://json-schema.org/understanding-json-schema/reference/string#length) keyword | | `max_length` | The maximum length of the string | [`maxLength`](https://json-schema.org/understanding-json-schema/reference/string#length) keyword | | `strip_whitespace` | Whether to remove leading and trailing whitespace | N/A | | `to_upper` | Whether to convert the string to uppercase | N/A | | `to_lower` | Whether to convert the string to lowercase | N/A | | `ascii_only` | Whether to allow only ASCII characters | N/A | These constraints can be provided using the [`StringConstraints`][pydantic.types.StringConstraints] metadata type, or using the [`Field()`][pydantic.Field] function (except for `strip_whitespace`, `to_upper`, `to_lower` and `ascii_only`). The [`annotated-types`](https://github.com/annotated-types/annotated-types) library also provides the `MinLen`, `MaxLen` and `Len` metadata types, as well as the `LowerCase`, `UpperCase`, `IsDigit` and `IsAscii` predicates (must be parameterized with `str`, e.g. `LowerCase[str]`). [](){#pattern-constraint-note} !!! note "`pattern` constraint" By default, Pydantic will use the [`regex`](https://docs.rs/regex) Rust crate to enforce the `pattern` constraint. The regex engine can be controlled using the [`regex_engine`][pydantic.ConfigDict.regex_engine] configuration value. If a compiled [regular expression object][re.Pattern] is used for `pattern`, the Python engine will automatically be used. While the JSON Schema specification [recommends](https://json-schema.org/draft/2020-12/json-schema-core#name-regular-expressions) using patterns valid according to dialect described in [ECMA-262](https://262.ecma-international.org/11.0/index.html#sec-patterns), Pydantic will *not* enforce it.

Strictness

In [strict mode](../concepts/strict_mode.md), only string values are valid. Pydantic provides the [`StrictStr`][pydantic.types.StrictStr] type as a convenience to [using the `Strict()` metadata class](../concepts/strict_mode.md#using-the-strict-metadata-class).

Example

```python from typing import Annotated from pydantic import BaseModel, StringConstraints class StringModel(BaseModel): str_value: str = "" constrained_str_value: Annotated[str, StringConstraints(to_lower=True)] = "" print(StringModel(str_value="test").str_value) #> test print(StringModel(constrained_str_value='TEST').constrained_str_value) #> test ``` ## Bytes Built-in type: [`bytes`][]. See also: [`ByteSize`][pydantic.types.ByteSize].

Validation

* [`bytes`][] instances are validated as is. * Strings and [`bytearray`][] instances are converted as bytes, following the [`val_json_bytes`][pydantic.ConfigDict.val_json_bytes] configuration value (despite its name, it applies to both Python and JSON modes).

Constraints

Strings support the following constraints: | Constraint | Description | JSON Schema | | ------------------ | --------------------------------| -------------------------------------------------------------------------------------------------| | `min_length` | The minimum length of the bytes | [`minLength`](https://json-schema.org/understanding-json-schema/reference/string#length) keyword | | `max_length` | The maximum length of the bytes | [`maxLength`](https://json-schema.org/understanding-json-schema/reference/string#length) keyword | The `MinLen` and `MaxLen` metadata types from the [`annotated-types`](https://github.com/annotated-types/annotated-types) library can also be used.

Strictness

In [strict mode](../concepts/strict_mode.md), only [`bytes`][] instances are valid. Pydantic provides the [`StrictBytes`][pydantic.types.StrictBytes] type as a convenience to [using the `Strict()` metadata class](../concepts/strict_mode.md#using-the-strict-metadata-class). In JSON mode, strict mode has no effect. [](){#number-types} ## Numbers Pydantic supports the following numeric types from the Python standard library: [](){#int} ### Integers Built-in type: [`int`][].

Validation

* Integers are validated as-is. * Strings and bytes are attempted to be converted to integers and validated as-is (see the [jiter implementation](https://docs.rs/jiter/latest/jiter/enum.NumberInt.html#impl-TryFrom%3C%26%5Bu8%5D%3E-for-NumberInt) for details). * Floats are validated as integers, provided the float input is not infinite or a NaN (not-a-number) and the fractional part is 0. * [`Decimal`][decimal.Decimal] instances, provided they are [finite][decimal.Decimal.is_finite] and the denominator is 1. * [`Fraction`][fractions.Fraction] instances, provided they are [integers][fractions.Fraction.is_integer]. * [Enums][enum] are converted using the [`value`][enum.Enum.value] attribute.

Constraints

Integers support the following constraints (numbers must be coercible to integers): | Constraint | Description | JSON Schema | | ------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------- | | `le` | The value must be less than or equal to this number | [`maximum`](https://json-schema.org/understanding-json-schema/reference/numeric#range) keyword | | `ge` | The value must be greater than or equal to this number | [`minimum`](https://json-schema.org/understanding-json-schema/reference/numeric#range) keyword | | `lt` | The value must be strictly less than this number | [`exclusiveMaximum`](https://json-schema.org/understanding-json-schema/reference/numeric#range) keyword | | `gt` | The value must be strictly greater than this number | [`exclusiveMinimum`](https://json-schema.org/understanding-json-schema/reference/numeric#range) keyword | | `multiple_of` | The value must be a multiple of this number | [`multipleOf`](https://json-schema.org/understanding-json-schema/reference/numeric#multiples) keyword | These constraints can be provided using the [`Field()`][pydantic.Field] function. The `Le`, `Ge`, `Lt`, `Gt` and `MultipleOf` metadata types from the [`annotated-types`](https://github.com/annotated-types/annotated-types) library can also be used. Pydantic also provides the following types to further constrain the allowed integer values: * [`PositiveInt`][pydantic.types.PositiveInt]: Requires the input to be greater than zero. * [`NegativeInt`][pydantic.types.NegativeInt]: Requires the input to be less than zero. * [`NonPositiveInt`][pydantic.types.NonPositiveInt]: Requires the input to be less than or equal to zero. * [`NonNegativeInt`][pydantic.types.NonNegativeInt]: Requires the input to be greater than or equal to zero.

Strictness

In [strict mode](../concepts/strict_mode.md), only integer values are valid. Pydantic provides the [`StrictInt`][pydantic.types.StrictInt] type as a convenience to [using the `Strict()` metadata class](../concepts/strict_mode.md#using-the-strict-metadata-class). [](){#float} ### Floats Built-in type: [`float`][].

Validation

* Floats are validated as-is. * String and bytes are attempted to be converted to floats and validated as-is. (see the [Rust implementation](https://doc.rust-lang.org/src/core/num/dec2flt/mod.rs.html) for details). * If the input has a [`__float__()`][object.__float__] method, it will be called to convert the input into a float. If `__float__()` is not defined, it falls back to [`__index__()`][object.__index__]. This includes (but not limited to) the [`Decimal`][decimal.Decimal] and [`Fraction`][fractions.Fraction] types.

Constraints

Floats support the following constraints: | Constraint | Description | JSON Schema | | --------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | | `le` | The value must be less than or equal to this number | [`maximum`](https://json-schema.org/understanding-json-schema/reference/numeric#range) keyword | | `ge` | The value must be greater than or equal to this number | [`minimum`](https://json-schema.org/understanding-json-schema/reference/numeric#range) keyword | | `lt` | The value must be strictly less than this number | [`exclusiveMaximum`](https://json-schema.org/understanding-json-schema/reference/numeric#range) keyword | | `gt` | The value must be strictly greater than this number | [`exclusiveMinimum`](https://json-schema.org/understanding-json-schema/reference/numeric#range) keyword | | `multiple_of` | The value must be a multiple of this number | [`multipleOf`](https://json-schema.org/understanding-json-schema/reference/numeric#multiples) keyword | | `allow_inf_nan` | Whether to allow NaN (not-a-number) and infinite values | N/A | These constraints can be provided using the [`Field()`][pydantic.Field] function. The [`annotated-types`](https://github.com/annotated-types/annotated-types) library also provides the `Le`, `Ge`, `Lt`, `Gt` and `MultipleOf` metadata types, as well as the `IsFinite`, `IsNotFinite`, `IsNan`, `IsNotNan`, `IsAscii`, `IsInfinite` and `IsNotInfinite` predicates (must be parameterized with `float`, e.g. `IsFinite[float]`). The [`AllowInfNan`][pydantic.types.AllowInfNan] type can also be used. Pydantic also provides the following types as convenience aliases: * [`PositiveFloat`][pydantic.types.PositiveFloat]: Requires the input to be greater than zero. * [`NegativeFloat`][pydantic.types.NegativeFloat]: Requires the input to be less than zero. * [`NonPositiveFloat`][pydantic.types.NonPositiveFloat]: Requires the input to be less than or equal to zero. * [`NonNegativeFloat`][pydantic.types.NonNegativeFloat]: Requires the input to be greater than or equal to zero. * [`FiniteFloat`][pydantic.types.FiniteFloat]: Prevents NaN (not-a-number) and infinite values.

Strictness

In [strict mode](../concepts/strict_mode.md), only float values and inputs having a [`__float__()`][object.__float__] or [`__index__()`][object.__index__] method are valid. Pydantic provides the [`StrictFloat`][pydantic.types.StrictFloat] type as a convenience to [using the `Strict()` metadata class](../concepts/strict_mode.md#using-the-strict-metadata-class). [](){#enumintenum} ### Integer enums Standard library type: [`enum.IntEnum`][].

Validation

* If the [`enum.IntEnum`][] type is used directly, any [`enum.IntEnum`][] instance is validated as-is * If an [`enum.IntEnum`][] subclass is used as a type, any enum member or value that correspond to the enum members values is validated as-is. See [Enums](#enums) for more details. [](){#decimaldecimal} ### Decimals Standard library type: [`decimal.Decimal`][].

Validation

* [`Decimal`][decimal.Decimal] instances are validated as is. * Any value accepted by the [`Decimal`][decimal.Decimal] constructor.

Constraints

Decimals support the following constraints (numbers must be coercible to decimals): | Constraint | Description | JSON Schema | | ---------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | `le` | The value must be less than or equal to this number | [`maximum`](https://json-schema.org/understanding-json-schema/reference/numeric#range) keyword | | `ge` | The value must be greater than or equal to this number | [`minimum`](https://json-schema.org/understanding-json-schema/reference/numeric#range) keyword | | `lt` | The value must be strictly less than this number | [`exclusiveMaximum`](https://json-schema.org/understanding-json-schema/reference/numeric#range) keyword | | `gt` | The value must be strictly greater than this number | [`exclusiveMinimum`](https://json-schema.org/understanding-json-schema/reference/numeric#range) keyword | | `multiple_of` | The value must be a multiple of this number | [`multipleOf`](https://json-schema.org/understanding-json-schema/reference/numeric#multiples) keyword | | `allow_inf_nan` | Whether to allow NaN (not-a-number) and infinite values | N/A | | `max_digits` | The maximum number of decimal digits allowed. The zero before the decimal point and trailing zeros are not counted. | [`pattern`](https://json-schema.org/understanding-json-schema/reference/string#regexp) keyword, to describe the string pattern | | `decimal_places` | The maximum number of decimal places allowed. Trailing zeros are not counted. | [`pattern`](https://json-schema.org/understanding-json-schema/reference/string#regexp) keyword, to describe the string pattern | Note that the JSON Schema [`pattern`](https://json-schema.org/understanding-json-schema/reference/string#regexp) keyword will be specified in the JSON Schema to describe the string pattern in all cases (and can vary if `max_digits` and/or `decimal_places` is specified). These constraints can be provided using the [`Field()`][pydantic.Field] function. The `Le`, `Ge`, `Lt`, `Gt` and `MultipleOf` metadata types from the [`annotated-types`](https://github.com/annotated-types/annotated-types) library and the [`AllowInfNan`][pydantic.types.AllowInfNan] type can also be used.

Strictness

In [strict mode](../concepts/strict_mode.md), only [`decimal.Decimal`][] instances are accepted. In JSON mode, strict mode has no effect.

Serialization

In [Python mode](../concepts/serialization.md#python-mode), [`Decimal`][decimal.Decimal] instances are serialized as is. In [JSON mode](../concepts/serialization.md#json-mode), they are serialized as strings. A [serializer](../concepts/serialization.md#field-plain-serializer) can be used to override this behavior: ```python from decimal import Decimal from typing import Annotated from pydantic import BaseModel, PlainSerializer class Model(BaseModel): f: Annotated[Decimal, PlainSerializer(float, when_used='json')] my_model = Model(f=Decimal('2.1')) print(my_model.model_dump()) # (1)! #> {'f': Decimal('2.1')} print(my_model.model_dump_json()) # (2)! #> {"f":2.1} ``` 1. In Python mode, `f`remains a [`Decimal`][decimal.Decimal] instance. 2. In JSON mode, `f` is serialized as a float. [](){#complex} ### Complex numbers /// version-added | v2.9 /// Built-in type: [`complex`][].

Validation

* [`complex`][] instances are validated as-is. * In Python mode, data is validated using the [`complex()`][complex] constructor. * In JSON mode, string are validated using the [`complex()`][complex] constructor, numbers (integers and floats) are used as the real part.

Strictness

In [strict mode](../concepts/strict_mode.md), only [`complex`][] instances are accepted. In JSON mode, only strings that are accepted by the [`complex()`][complex] constructor are allowed.

Serialization

In [Python mode](../concepts/serialization.md#python-mode), [`complex`][] instances are serialized as is. In [JSON mode](../concepts/serialization.md#json-mode), they are serialized as strings. [](){#fractionsfraction} ### Fractions /// version-added | v2.10 /// Standard library type: [`fractions.Fraction`][].

Validation

* [`Fraction`][fractions.Fraction] instances are validated as is. * Floats, strings and [`decimal.Decimal`][] instances are validated using the [`Fraction()`][fractions.Fraction] constructor.

Strictness

In [strict mode](../concepts/strict_mode.md), only [`Fraction`][fractions.Fraction] instances are accepted. In JSON mode, strict mode has no effect.

Serialization

Fractions are serialized as strings, both in [Python](../concepts/serialization.md#python-mode) and [JSON](../concepts/serialization.md#json-mode) modes. [](){#datetime-types} ## Date and time types Pydantic supports the following [date and time](https://docs.python.org/library/datetime.html#available-types) types from the [`datetime`][] standard library: [](){#datetimedatetime} ### Datetimes Standard library type: [`datetime.datetime`][].

Validation

* [`datetime`][datetime.datetime] instances are validated as is. * Strings and bytes are validated in two ways: * Strings complying to the [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339) format (both datetime and date). See the [speedate](https://docs.rs/speedate/) documentation for more details. * Unix timestamps, both as seconds or milliseconds sinch the [epoch](https://en.wikipedia.org/wiki/Unix_time). See the [`val_temporal_unit`][pydantic.ConfigDict.val_temporal_unit] configuration value for more details. * Integers and floats (or types that can be coerced as integers or floats) are validated as unix timestamps, following the same semantics as strings. * [`datetime.date`][] instances are accepted, and converted to a [`datetime`][datetime.datetime] instance by setting the [`hour`][datetime.datetime.hour], [`minute`][datetime.datetime.minute], [`second`][datetime.datetime.second] and [`microsecond`][datetime.datetime.microsecond] attributes to `0`, and the [`tzinfo`][datetime.datetime.tzinfo] attribute to `None`. !!! note Named timezone support (as specified in [RFC 9557](https://datatracker.ietf.org/doc/html/rfc9557.html)) can be tracked in [this issue](https://github.com/pydantic/pydantic/issues/12252).

Serialization

In [Python mode](../concepts/serialization.md#python-mode), [`datetime`][datetime.datetime] instances are serialized as is. In [JSON mode](../concepts/serialization.md#json-mode), they are serialized as strings.

Constraints

Datetimes support the following constraints (constraint values must be coercible to a [`datetime`][datetime.datetime] instance): | Constraint | Description | JSON Schema | | ---------- | -------------------------------------------------------- | ----------- | | `le` | The value must be less than or equal to this datetime | N/A | | `ge` | The value must be greater than or equal to this datetime | N/A | | `lt` | The value must be strictly less than this datetime | N/A | | `gt` | The value must be strictly greater than this datetime | N/A | These constraints can be provided using the [`Field()`][pydantic.Field] function. The `Le`, `Ge`, `Lt` and `Gt` metadata types from the [`annotated-types`](https://github.com/annotated-types/annotated-types) library can also be used. Pydantic also provides the following types to further constrain the allowed datetime values: * [`AwareDatetime`][pydantic.types.AwareDatetime]: Requires the input to have a timezone. * [`NaiveDatetime`][pydantic.types.NaiveDatetime]: Requires the input to *not* have a timezone. * [`PastDatetime`][pydantic.types.PastDatetime]: Requires the input to be in the past when validated. * [`FutureDatetime`][pydantic.types.FutureDatetime]: Requires the input to be in the future when validated.

Strictness

In [strict mode](../concepts/strict_mode.md), only [`datetime`][datetime.datetime] instances are accepted. In JSON mode, only strings complying to the [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339) format (*only* datetime) or as unix timestamps are accepted.

Example

```python from datetime import datetime from typing import Annotated from pydantic import AwareDatetime, BaseModel, Field class Event(BaseModel): dt: Annotated[AwareDatetime, Field(gt=datetime(2000, 1, 1))] event = Event(dt='2032-04-23T10:20:30.400+02:30') print(event.model_dump()) """ {'dt': datetime.datetime(2032, 4, 23, 10, 20, 30, 400000, tzinfo=TzInfo(9000))} """ print(event.model_dump_json()) #> {"dt":"2032-04-23T10:20:30.400000+02:30"} ``` [](){#datetimedate} ### Dates Standard library type: [`datetime.date`][].

Validation

* [`date`][datetime.date] instances are validated as is. * Strings and bytes are validated in two ways: * Strings complying to the [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339) date format. See the [speedate](https://docs.rs/speedate/) documentation for more details. * Unix timestamps, both as seconds or milliseconds sinch the [epoch](https://en.wikipedia.org/wiki/Unix_time). See the [`val_temporal_unit`][pydantic.ConfigDict.val_temporal_unit] configuration value for more details. * If the validation fails, the input can be [validated as a datetime](#datetimes) (including as numbers), provided that the time component is 0 and that it is naive.

Serialization

In [Python mode](../concepts/serialization.md#python-mode), [`date`][datetime.date] instances are serialized as is. In [JSON mode](../concepts/serialization.md#json-mode), they are serialized as strings.

Constraints

Dates support the following constraints (constraint values must be coercible to a [`date`][datetime.date] instance): | Constraint | Description | JSON Schema | | ---------- | ---------------------------------------------------- | ----------- | | `le` | The value must be less than or equal to this date | N/A | | `ge` | The value must be greater than or equal to this date | N/A | | `lt` | The value must be strictly less than this date | N/A | | `gt` | The value must be strictly greater than this date | N/A | These constraints can be provided using the [`Field()`][pydantic.Field] function. The `Le`, `Ge`, `Lt` and `Gt` metadata types from the [`annotated-types`](https://github.com/annotated-types/annotated-types) library can also be used. Pydantic also provides the following types to further constrain the allowed date values: * [`PastDate`][pydantic.types.PastDate]: Requires the input to be in the past when validated. * [`FutureDate`][pydantic.types.FutureDate]: Requires the input to be in the future when validated.

Strictness

In [strict mode](../concepts/strict_mode.md), only [`date`][datetime.date] instances are accepted. In JSON mode, only strings complying to the [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339) format (*only* date) or as unix timestamps are accepted.

Example

```python from datetime import date from pydantic import BaseModel class Birthday(BaseModel): d: date my_birthday = Birthday(d=1679616000.0) print(my_birthday.model_dump()) #> {'d': datetime.date(2023, 3, 24)} print(my_birthday.model_dump_json()) #> {"d":"2023-03-24"} ``` [](){#datetimetime} ### Time Standard library type: [`datetime.time`][].

Validation

* [`time`][datetime.time] instances are validated as is. * Strings and bytes are validated according to the [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339) time format. * Integers and floats (or values that can be coerced to such numbers) are validated as seconds. The value should not exceed 86 399.

Serialization

In [Python mode](../concepts/serialization.md#python-mode), [`time`][datetime.time] instances are serialized as is. In [JSON mode](../concepts/serialization.md#json-mode), they are serialized as strings. !!! note Named timezones from the [IANA time zone database](https://www.iana.org/time-zones) (see the [`zoneinfo`][] module) are *not* serialized with time objects. This is consistent with the [`time.isoformat()`][datetime.time.isoformat] method.

Constraints

Time support the following constraints (constraint values must be coercible to a [`time`][datetime.time] instance): | Constraint | Description | JSON Schema | | ---------- | ---------------------------------------------------- | ----------- | | `le` | The value must be less than or equal to this time | N/A | | `ge` | The value must be greater than or equal to this time | N/A | | `lt` | The value must be strictly less than this time | N/A | | `gt` | The value must be strictly greater than this time | N/A | These constraints can be provided using the [`Field()`][pydantic.Field] function. The `Le`, `Ge`, `Lt` and `Gt` metadata types from the [`annotated-types`](https://github.com/annotated-types/annotated-types) library can also be used.

Strictness

In [strict mode](../concepts/strict_mode.md), only [`time`][datetime.time] instances are accepted. In JSON mode, only strings complying to the [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339) format are accepted.

Example

```python from datetime import time from pydantic import BaseModel class Meeting(BaseModel): t: time m = Meeting(t=time(4, 8, 16)) print(m.model_dump()) #> {'t': datetime.time(4, 8, 16)} print(m.model_dump_json()) #> {"t":"04:08:16"} ``` [](){#datetimetimedelta} ### Timedeltas Standard library type: [`datetime.timedelta`][].

Validation

* [`timedelta`][datetime.timedelta] instances are validated as is. * Strings and bytes are validated according to the [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339) time format. * Integers and floats (or values that can be coerced to such numbers) are validated as seconds.

Constraints

Timedeltas support the following constraints (constraint values must be coercible to a [`timedata`][datetime.timedelta] instance): | Constraint | Description | JSON Schema | | ---------- | ---------------------------------------------------- -----| ----------- | | `le` | The value must be less than or equal to this timedelta | N/A | | `ge` | The value must be greater than or equal to this timedelta | N/A | | `lt` | The value must be strictly less than this timedelta | N/A | | `gt` | The value must be strictly greater than this timedelta | N/A | These constraints can be provided using the [`Field()`][pydantic.Field] function. The `Le`, `Ge`, `Lt` and `Gt` metadata types from the [`annotated-types`](https://github.com/annotated-types/annotated-types) library can also be used.

Serialization

In [Python mode](../concepts/serialization.md#python-mode), [`timedelta`][datetime.timedelta] instances are serialized as is. In [JSON mode](../concepts/serialization.md#json-mode), they are serialized as strings.

Strictness

In [strict mode](../concepts/strict_mode.md), only [`timedelta`][datetime.timedelta] instances are accepted. In JSON mode, only strings complying to the [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339) format are accepted.

Example

```python from datetime import timedelta from pydantic import BaseModel class Model(BaseModel): td: timedelta m = Model(td='P3DT12H30M5S') print(m.model_dump()) #> {'td': datetime.timedelta(days=3, seconds=45005)} print(m.model_dump_json()) #> {"td":"P3DT12H30M5S"} ``` [](){#enum} ## Enums Standard library type: [`enum.Enum`][].

Validation

* If the [`enum.Enum`][] type is used directly, any [`enum.Enum`][] instance is validated as-is. * If an [`enum.Enum`][] subclass is used as a type, any enum member or value that correspond to the enum members [values][enum.Enum.value] is validated as-is.

Serialization

In [Python mode](../concepts/serialization.md#python-mode), enum instances are serialized as is. The [`use_enum_values`][pydantic.ConfigDict.use_enum_values] configuration value can be set to use the enum [value][enum.Enum.value] during validation (so that it is also used during serialization). In [JSON mode](../concepts/serialization.md#json-mode), enum instances are serialized using their [value][enum.Enum.value].

Example

```python from enum import Enum, IntEnum 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()) #> fruit= tool= print(CookingModel(tool=2, fruit='banana')) #> fruit= tool= try: CookingModel(fruit='other') except ValidationError as e: print(e) """ 1 validation error for CookingModel fruit Input should be 'pear' or 'banana' [type=enum, input_value='other', input_type=str] """ ``` ## None types Supported types: [`None`][], [`NoneType`][types.NoneType] or `Literal[None]` (they are [equivalent](https://typing.readthedocs.io/en/latest/spec/special-types.html#none)). Allows only `None` as a value. ## Generic collection types Pydantic supports a wide variety of generic collection types, both built-ins (such as [`list`][]) and abstract base classes from the [`collections.abc`][] module (such as [`Sequence`][collections.abc.Sequence]). In most cases, it is recommended to make use of the built-in types over the abstract ones. Due to [data coercion](../concepts/models.md#data-conversion), using [`list`][] or [`tuple`][] will allow most other iterables as input, with better performance. !!! note "Strictness on collection types" When applying [strict mode](../concepts/strict_mode.md) on collection types, strictness will *not* apply to the inner types. This may change in the future, see [this issue](https://github.com/pydantic/pydantic/issues/12319). ### Lists Built-in type: [`list`][] (deprecated alias: [`typing.List`][]).

Validation

* Allows [`list`][], [`tuple`][], [`set`][] and [`frozenset`][] instances, or any iterable that is *not* a [string][str], [bytes][], [bytearray][], [dict][] or [mapping][]. Produces a [`list`][] instance. * If a generic parameter is provided, the appropriate validation is applied to all items of the list.

Constraints

Lists support the following constraints: | Constraint | Description | JSON Schema | |--------------|---------------------------------------------|------------------------------------------------------------------------------------------------| | `min_length` | The list must have at least this many items | [`minItems`](https://json-schema.org/understanding-json-schema/reference/array#length) keyword | | `max_length` | The list must have at most this many items | [`maxItems`](https://json-schema.org/understanding-json-schema/reference/array#length) keyword | These constraints can be provided using the [`Field()`][pydantic.Field] function. The `MinLen` and `MaxLen` metadata types from the [`annotated-types`](https://github.com/annotated-types/annotated-types) library can also be used.

Strictness

In [strict mode](../concepts/strict_mode.md), only [`list`][] instances are valid. Strict mode does *not* apply to the items of the list. The strict constraint must be applied to the parameter type for this to work.

Example

```python from typing import Optional from pydantic import BaseModel, Field class Model(BaseModel): simple_list: Optional[list[object]] = None list_of_ints: Optional[list[int]] = Field(default=None, strict=True) 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] ``` ### Tuples Built-in type: [`tuple`][] (deprecated alias: [`typing.Tuple`][]). !!! note [Unpacked tuple types](https://typing.python.org/en/latest/spec/generics.html#unpacking-tuple-types) (as specified by [PEP 646](https://peps.python.org/pep-0646/)) are *not* yet supported, and can be tracked in [this issue](https://github.com/pydantic/pydantic/issues/5952).

Validation

* Allows [`tuple`][], [`list`][], [`set`][] and [`frozenset`][] instances, or any iterable that is *not* a [string][str], [bytes][], [bytearray][], [dict][] or [mapping][]. Produces a [`tuple`][] instance. * Appropriate validation is applied to items of the tuple, if [element types](https://typing.python.org/en/latest/spec/tuples.html#tuple-type-form) are specified.

Constraints

Lists support the following constraints: | Constraint | Description | JSON Schema | |--------------|----------------------------------------------|------------------------------------------------------------------------------------------------| | `min_length` | The tuple must have at least this many items | [`minItems`](https://json-schema.org/understanding-json-schema/reference/array#length) keyword | | `max_length` | The tuple must have at most this many items | [`maxItems`](https://json-schema.org/understanding-json-schema/reference/array#length) keyword | These constraints can be provided using the [`Field()`][pydantic.Field] function. The `MinLen` and `MaxLen` metadata types from the [`annotated-types`](https://github.com/annotated-types/annotated-types) library can also be used. Additionally, the [`prefixItems`](https://json-schema.org/understanding-json-schema/reference/array#tupleValidation) JSON Schema keyword may be used depending on the tuple shape.

Strictness

In [strict mode](../concepts/strict_mode.md), only [`tuple`][] instances are valid. Strict mode does *not* apply to the items of the tuple. The strict constraint must be applied to the parameter types for this to work.

Example

```python from typing import Optional from pydantic import BaseModel class Model(BaseModel): simple_tuple: Optional[tuple] = None tuple_of_different_types: Optional[tuple[int, float, bool]] = None print(Model(simple_tuple=[1, 2, 3, 4]).simple_tuple) #> (1, 2, 3, 4) print(Model(tuple_of_different_types=[3, 2, 1]).tuple_of_different_types) #> (3, 2.0, True) ``` [](){#typingnamedtuple} ### Named tuples Standard library type: [`typing.NamedTuple`][] (and types created by the [`collections.namedtuple()`][collections.namedtuple] factory function – each field will implicitly have the type [`Any`][typing.Any]).

Validation

* Allows [`tuple`][] and [`list`][] instances. Validate each item according to the field definition. * Allows [`dict`][] instances. Keys must match the named tuple field names, and values are validated according to the field definition.

Serialization

In [Python mode](../concepts/serialization.md#python-mode), named tuples are serialized as tuples. In [JSON mode](../concepts/serialization.md#json-mode), they are serialized as arrays.

Example

```python from typing import NamedTuple from pydantic import BaseModel class Point(NamedTuple): x: int y: int class Model(BaseModel): p: Point model = Model(p=('1', 2)) print(model.model_dump()) #> {'p': (1, 2)} ``` ### Sets Types: [`set`][] (or [`collections.abc.MutableSet`][]) and [`frozenset`][] (or [`collections.abc.Set`][]) (deprecated aliases: [`typing.Set`][] and [`typing.FrozenSet`][]).

Validation

* Allows [`set`][], [`frozenset`][], [`tuple`][] and [`list`][] instances, or any iterable that is *not* a [string][str], [bytes][], [bytearray][], [dict][] or [mapping][]. Produces a [`set`][] or [`frozenset`][] instance. * If a generic parameter is provided, the appropriate validation is applied to all items of the set/frozenset.

Constraints

Sets support the following constraints: | Constraint | Description | JSON Schema | |--------------|--------------------------------------------|------------------------------------------------------------------------------------------------| | `min_length` | The set must have at least this many items | [`minItems`](https://json-schema.org/understanding-json-schema/reference/array#length) keyword | | `max_length` | The set must have at most this many items | [`maxItems`](https://json-schema.org/understanding-json-schema/reference/array#length) keyword | These constraints can be provided using the [`Field()`][pydantic.Field] function. The `MinLen` and `MaxLen` metadata types from the [`annotated-types`](https://github.com/annotated-types/annotated-types) library can also be used.

Strictness

In [strict mode](../concepts/strict_mode.md), only [`set`][]/[`frozenset`][] instances are valid. Strict mode does *not* apply to the items of the set. The strict constraint must be applied to the parameter type for this to work.

Serialization

In [Python mode](../concepts/serialization.md#python-mode), sets are serialized as is. In [JSON mode](../concepts/serialization.md#json-mode), they are serialized as arrays.

Example

```python from typing import Optional from pydantic import BaseModel class Model(BaseModel): simple_set: Optional[set] = None set_of_ints: Optional[frozenset[int]] = None print(Model(simple_set=['1', '2', '3']).simple_set) #> {'1', '2', '3'} print(Model(set_of_ints=['1', '2', '3']).set_of_ints) #> frozenset({1, 2, 3}) ```

JSON Schema

Pydantic does best effort to sort default values that are [`collections.abc.Set`][] instances. ### Deque Standard library type: [`collections.deque`][] (deprecated alias: [`typing.Deque`][]).

Validation

Values are first validated as a [list](#lists), and then passed to the [`deque`][collections.deque] constructor.

Constraints

Deques support the following constraints: | Constraint | Description | JSON Schema | |--------------|----------------------------------------------|------------------------------------------------------------------------------------------------| | `min_length` | The deque must have at least this many items | [`minItems`](https://json-schema.org/understanding-json-schema/reference/array#length) keyword | | `max_length` | The deque must have at most this many items | [`maxItems`](https://json-schema.org/understanding-json-schema/reference/array#length) keyword | These constraints can be provided using the [`Field()`][pydantic.Field] function. The `MinLen` and `MaxLen` metadata types from the [`annotated-types`](https://github.com/annotated-types/annotated-types) library can also be used.

Strictness

In [strict mode](../concepts/strict_mode.md), only [`deque`][collections.deque] instances are valid. Strict mode does *not* apply to the items of the deque. The strict constraint must be applied to the parameter type for this to work.

Serialization

In [Python mode](../concepts/serialization.md#python-mode), deques are serialized as is. In [JSON mode](../concepts/serialization.md#json-mode), they are serialized as arrays.

Example

```python from collections import deque from pydantic import BaseModel class Model(BaseModel): deque: deque[int] print(Model(deque=[1, 2, 3]).deque) #> deque([1, 2, 3]) ``` [](){#typingsequence} ### Sequences Standard library type: [`collections.abc.Sequence`][] (deprecated alias: [`typing.Sequence`][]). In most cases, you will want to use the built-in types (such as [list](#lists) or [tuple](#tuples)) as [type coercion](../concepts/models.md#data-conversion) will apply. The [`Sequence`][collections.abc.Sequence] type can be used when you want to preserve the input type during serialization.

Validation

Any [`collections.abc.Sequence`][] instance (expect strings and bytes) is accepted. It is converted to a list using the [`list()`][list] constructor, and then converted back to the original input type. !!! warning "Strings aren't treated as sequences" While strings are technically valid sequence instances, this is frequently not intended as is a common source of bugs. As a result, Pydantic will *not* accept strings and bytes for the [`Sequence`][collections.abc.Sequence] type (see example below).

Constraints

Sequences support the following constraints: | Constraint | Description | JSON Schema | |--------------|-------------------------------------------------|------------------------------------------------------------------------------------------------| | `min_length` | The sequence must have at least this many items | [`minItems`](https://json-schema.org/understanding-json-schema/reference/array#length) keyword | | `max_length` | The sequence must have at most this many items | [`maxItems`](https://json-schema.org/understanding-json-schema/reference/array#length) keyword | These constraints can be provided using the [`Field()`][pydantic.Field] function. The `MinLen` and `MaxLen` metadata types from the [`annotated-types`](https://github.com/annotated-types/annotated-types) library can also be used.

Serialization

In [Python mode](../concepts/serialization.md#python-mode), sequences are serialized as is. In [JSON mode](../concepts/serialization.md#json-mode), they are serialized as arrays.

Example

```python from collections.abc import Sequence from pydantic import BaseModel, ValidationError class Model(BaseModel): sequence_of_strs: Sequence[str] print(Model(sequence_of_strs=['a', 'bc']).sequence_of_strs) #> ['a', 'bc'] print(Model(sequence_of_strs=('a', 'bc')).sequence_of_strs) #> ('a', 'bc') try: Model(sequence_of_strs='abc') except ValidationError as e: print(e) """ 1 validation error for Model sequence_of_strs 'str' instances are not allowed as a Sequence value [type=sequence_str, input_value='abc', input_type=str] """ ``` ### Dictionaries Built-in type: [`dict`][].

Validation

* [`dict`][] instances are accepted as is. * [mappings][mapping] instances are accepted and coerced to a [`dict`][]. * If generic parameters for keys and values are provided, the appropriate validation is applied.

Constraints

Dictionaries support the following constraints: | Constraint | Description | JSON Schema | |--------------|---------------------------------------------------|------------------------------------------------------------------------------------------------| | `min_length` | The dictionary must have at least this many items | [`minItems`](https://json-schema.org/understanding-json-schema/reference/array#length) keyword | | `max_length` | The dictionary must have at most this many items | [`maxItems`](https://json-schema.org/understanding-json-schema/reference/array#length) keyword | These constraints can be provided using the [`Field()`][pydantic.Field] function. The `MinLen` and `MaxLen` metadata types from the [`annotated-types`](https://github.com/annotated-types/annotated-types) library can also be used.

Strictness

In [strict mode](../concepts/strict_mode.md), only [`dict`][] instances are valid. Strict mode does *not* apply to the keys and values of the dictionaries. The strict constraint must be applied to the parameter types for this to work.

Example

```python from pydantic import BaseModel, ValidationError class Model(BaseModel): x: dict[str, int] m = Model(x={'foo': 1}) print(m.model_dump()) #> {'x': {'foo': 1}} try: Model(x='test') except ValidationError as e: print(e) """ 1 validation error for Model x Input should be a valid dictionary [type=dict_type, input_value='test', input_type=str] """ ``` [](){#typeddict} ### Typed dictionaries Standard library type: [`typing.TypedDict`][] (see also: the [typing specification](https://typing.python.org/en/latest/spec/typeddict.html)). !!! note Because of runtime limitations, Pydantic will require using the [`TypedDict`][typing_extensions.TypedDict] type from [`typing_extensions`][] when using Python 3.12 and lower. [`TypedDict`][typing.TypedDict] declares a dictionary type that expects all of its instances to have a certain set of keys where each key is associated with a value of a consistent type. This type [supports configuration](../concepts/config.md#configuration-on-other-supported-types).

Strictness

In [strict mode](../concepts/strict_mode.md), only [`dict`][] instances are valid (unlike mappings in lax mode). Strict mode does *not* apply to the values of the typed dictionary. The strict constraint must be applied to the value types for this to work.

Example

```python from typing_extensions import TypedDict from pydantic import TypeAdapter, ValidationError class User(TypedDict): name: str id: int ta = TypeAdapter(User) print(ta.validate_python({'name': 'foo', 'id': 1})) #> {'name': 'foo', 'id': 1} try: ta.validate_python({'name': 'foo'}) except ValidationError as e: print(e) """ 1 validation error for User id Field required [type=missing, input_value={'name': 'foo'}, input_type=dict] """ ``` [](){#typingiterable} ### Iterables Standard library type: [`collections.abc.Iterable`][] (deprecated alias: [`typing.Iterable`][]).

Validation

Iterables are lazily validated, and wrapped in an internal datastructure that can be iterated over (and will validate the items type while doing so). This means that even if you provide a concrete container such as a list, the validated type will *not* be of type [`list`][]. However, Pydantic will ensure that the input value is iterable by getting an [iterator][] from it (by calling [`iter()`][iter] on the value). It is recommended to use concrete collection types (such as [lists](#lists)) instead, unless you are using an infinite iterator (in which case eagerly validating the input would result in an infinite loop).

Example

```python from collections.abc import Iterable from pydantic import BaseModel, ValidationError class Model(BaseModel): f: Iterable[str] m = Model(f=[1, 2]) # Validates fine try: next(m.f) except ValidationError as e: print(e) """ 1 validation error for ValidatorIterator 0 Input should be a valid string [type=string_type, input_value=1, input_type=int] """ ``` ## Callable Standard library type: [`collections.abc.Callable`][] (deprecated alias: [`typing.Callable`][]).

Validation

Pydantic only validates that the input is a [callable][] (using the [`callable()`](https://docs.python.org/3/library/functions.html#callable) function). It does *not* validate the number of parameters or their type, nor the type of the return value. ```python from typing import Callable from pydantic import BaseModel class Foo(BaseModel): callback: Callable[[int], int] m = Foo(callback=lambda x: x) print(m) #> callback= at 0x0123456789ab> ```

Serialization

Callables are serialized as is. Callables can't be serialized in [JSON mode](../concepts/serialization.md#json-mode) (a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] is raised). [](){#ip-address-types} ## IP Addresses Standard library types: * [`ipaddress.IPv4Address`][] * [`ipaddress.IPv4Interface`][] * [`ipaddress.IPv4Network`][] * [`ipaddress.IPv6Address`][] * [`ipaddress.IPv6Interface`][] * [`ipaddress.IPv6Network`][] See also: the [`IPvAnyAddress`][pydantic.networks.IPvAnyAddress], [`IPvAnyInterface`][pydantic.networks.IPvAnyInterface] and [`IPvAnyNetwork`][pydantic.networks.IPvAnyNetwork] Pydantic types.

Validation

* Instances are validated as is. * Other input values are passed to the constructor of the relevant address type.

Strictness

In [strict mode](../concepts/strict_mode.md), only the address types are accepted. In JSON mode, strict mode has no effect.

Serialization

In [Python mode](../concepts/serialization.md#python-mode), IP addresses are serialized as is. In [JSON mode](../concepts/serialization.md#json-mode), they are serialized as strings. ## UUID Standard library type: [`uuid.UUID`][].

Validation

* [`UUID`][uuid.UUID] instances are validated as is. * Strings and bytes are validated as UUIDs, and casted to a [`UUID`][uuid.UUID] instance.

Constraints

The [`UUID`][uuid.UUID] type supports a `version` constraint. The [`UuidVersion`][pydantic.types.UuidVersion] metadata type can be used. Pydantic also provides the following types as convenience aliases: [`UUID1`][pydantic.types.UUID1], [`UUID3`][pydantic.types.UUID3], [`UUID4`][pydantic.types.UUID4], [`UUID5`][pydantic.types.UUID5], [`UUID6`][pydantic.types.UUID6], [`UUID7`][pydantic.types.UUID7], [`UUID8`][pydantic.types.UUID8].

Strictness

In [strict mode](../concepts/strict_mode.md), only [`UUID`][uuid.UUID] instances are accepted. In JSON mode, strict mode has no effect.

Serialization

In [Python mode](../concepts/serialization.md#python-mode), UUIDs are serialized as is. In [JSON mode](../concepts/serialization.md#json-mode), they are serialized as strings.

Example

```python from typing import Annotated from uuid import UUID from pydantic import BaseModel from pydantic.types import UUID7, UuidVersion class Model(BaseModel): u1: UUID7 u2: Annotated[UUID, UuidVersion(4)] print( Model( u1='01999b2c-8353-749b-8dac-859307fae22b', u2=UUID('125725f3-e1b4-44e3-90c3-1a20eab12da5'), ) ) """ u1=UUID('01999b2c-8353-749b-8dac-859307fae22b') u2=UUID('125725f3-e1b4-44e3-90c3-1a20eab12da5') """ ``` ## Type Built-in type: [`type`][] (deprecated alias: [`typing.Type`][]).

Validation

Allows any type that is a subclass of the type argument. For instance, with `type[str]`, allows the [`str`][] class or any [`str`][] subclass as an input. If no type argument is provided (i.e. `type` is used as an annotation), allow any class.

Serialization

Types are serialized as is. Types can't be serialized in [JSON mode](../concepts/serialization.md#json-mode) (a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] is raised). ```python from pydantic import BaseModel, ValidationError class Foo: pass class Bar(Foo): pass class Other: pass 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 for SimpleModel just_subclasses Input should be a subclass of Foo [type=is_subclass_of, input_value=, input_type=type] """ ``` [](){#typingliteral} ## Literals Typing construct: [`typing.Literal`][] (see also: the [typing specification](https://typing.python.org/en/latest/spec/literal.html#literal)). Literals can be used to only allow specific literal values. Note that Pydantic applies [strict mode](../concepts/strict_mode.md) behavior when validating literal values (see [this issue](https://github.com/pydantic/pydantic/issues/9991)).

Example

```python from typing import Literal from pydantic import BaseModel, ValidationError class Pie(BaseModel): flavor: Literal['apple', 'pumpkin'] quantity: Literal[1, 2] = 1 Pie(flavor='apple') Pie(flavor='pumpkin') try: Pie(flavor='cherry') except ValidationError as e: print(str(e)) """ 1 validation error for Pie flavor Input should be 'apple' or 'pumpkin' [type=literal_error, input_value='cherry', input_type=str] """ try: Pie(flavor='apple', quantity='1') except ValidationError as e: print(str(e)) """ 1 validation error for Pie quantity Input should be 1 or 2 [type=literal_error, input_value='1', input_type=str] """ ``` [](){#typingany} ## Any Types: [`typing.Any`][] or [`object`][]. Allows any value, including `None`. [](){#typinghashable} ## Hashables Standard library type: [`collections.abc.Hashable`][] (deprecated alias: [`typing.Hashable`][]).

Validation

Any value that is hashable (using `isinstance(value, Hashable)`). [](){#typingpattern} ## Regex patterns Standard library type: [`re.Pattern`][] (deprecated alias: [`typing.Pattern`][]).

Validation

* For [`Pattern`][re.Pattern] instances, check that the [`pattern`][re.Pattern.pattern] attribute is of the right type ([`str`][] or [`bytes`][] depending on the [`Pattern`][re.Pattern] type parameter). * If the type parameter is [`str`][] or [`bytes`][], input values of type [`str`][] (or [`bytes`][] respectively) are attempted to be compiled using [`re.compile()`][re.compile].

Serialization

In [Python mode](../concepts/serialization.md#python-mode), [`Pattern`][re.Pattern] instances are serialized as is. In [JSON mode](../concepts/serialization.md#json-mode), they are serialized as strings. [](){#pathlibpath} ## Paths Standard library types: * [`pathlib.Path`][]. * [`pathlib.PurePath`][]. * [`pathlib.PosixPath`][]. * [`pathlib.PurePosixPath`][]. * [`pathlib.PureWindowsPath`][]. * [`os.PathLike`][] (must be parameterized with [`str`][], [`bytes`][] or [`Any`][typing.Any]).

Validation

* Path instances are validated as is. * Strings are accepted and passed to the type constructor. If [`os.PathLike`][] was used, bytes are accepted if it was parameterized with the [`bytes`][] type.

Strictness

In [strict mode](../concepts/strict_mode.md), only Path instances are accepted. In JSON mode, strict mode has no effect.

Serialization

In [Python mode](../concepts/serialization.md#python-mode), Path instances are serialized as is. In [JSON mode](../concepts/serialization.md#json-mode), they are serialized as strings. pydantic-pydantic-ba0aa01/docs/api/type_adapter.md000066400000000000000000000000461517143232300223120ustar00rootroot00000000000000::: pydantic.type_adapter.TypeAdapter pydantic-pydantic-ba0aa01/docs/api/types.md000066400000000000000000000001451517143232300207750ustar00rootroot00000000000000::: pydantic.types options: show_root_heading: true merge_init_into_class: false pydantic-pydantic-ba0aa01/docs/api/validate_call.md000066400000000000000000000000451517143232300224140ustar00rootroot00000000000000::: pydantic.validate_call_decorator pydantic-pydantic-ba0aa01/docs/api/version.md000066400000000000000000000002261517143232300213160ustar00rootroot00000000000000::: pydantic.__version__ options: show_root_heading: true ::: pydantic.version.version_info options: show_root_heading: true pydantic-pydantic-ba0aa01/docs/badge/000077500000000000000000000000001517143232300176005ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/docs/badge/v1.json000066400000000000000000000017531517143232300210270ustar00rootroot00000000000000{ "label": "Pydantic", "message": "v1", "logoSvg": "", "logoWidth": 10, "labelColor": "#1e293b", "color": "#4CC61F" } pydantic-pydantic-ba0aa01/docs/badge/v2.json000066400000000000000000000017531517143232300210300ustar00rootroot00000000000000{ "label": "Pydantic", "message": "v2", "logoSvg": "", "logoWidth": 10, "labelColor": "#1e293b", "color": "#4CC61F" } pydantic-pydantic-ba0aa01/docs/concepts/000077500000000000000000000000001517143232300203545ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/docs/concepts/alias.md000066400000000000000000000331161517143232300217730ustar00rootroot00000000000000An alias is an alternative name for a field, used when serializing and deserializing data. You can specify an alias in the following ways: * `alias` on the [`Field`][pydantic.fields.Field] * must be a `str` * `validation_alias` on the [`Field`][pydantic.fields.Field] * can be an instance of `str`, [`AliasPath`][pydantic.aliases.AliasPath], or [`AliasChoices`][pydantic.aliases.AliasChoices] * `serialization_alias` on the [`Field`][pydantic.fields.Field] * must be a `str` * `alias_generator` on the [`Config`][pydantic.config.ConfigDict.alias_generator] * can be a callable or an instance of [`AliasGenerator`][pydantic.aliases.AliasGenerator] For examples of how to use `alias`, `validation_alias`, and `serialization_alias`, see [Field aliases](../concepts/fields.md#field-aliases). ## `AliasPath` and `AliasChoices` ??? api "API Documentation" [`pydantic.aliases.AliasPath`][pydantic.aliases.AliasPath]
[`pydantic.aliases.AliasChoices`][pydantic.aliases.AliasChoices]
Pydantic provides two special types for convenience when using `validation_alias`: `AliasPath` and `AliasChoices`. The `AliasPath` is used to specify a path to a field using aliases. For example: ```python {lint="skip"} from pydantic import BaseModel, Field, AliasPath class User(BaseModel): first_name: str = Field(validation_alias=AliasPath('names', 0)) last_name: str = Field(validation_alias=AliasPath('names', 1)) address: str = Field(validation_alias=AliasPath('contact', 'address')) user = User.model_validate({ # (1)! 'names': ['John', 'Doe'], 'contact': {'address': '221B Baker Street'} }) print(user) #> first_name='John' last_name='Doe' address='221B Baker Street' ``` 1. We are using [`model_validate()`][pydantic.BaseModel.model_validate] to validate a dictionary using the field aliases. Refer to documentation about [validating data](./models.md#validating-data) for more details. In the `'first_name'` field, we are using the alias `'names'` and the index `0` to specify the path to the first name. In the `'last_name'` field, we are using the alias `'names'` and the index `1` to specify the path to the last name. `AliasChoices` is used to specify a list of choices of aliases. Choices that appear first in the list will have higher priority during validation. For example: ```python {lint="skip"} from pydantic import BaseModel, Field, AliasChoices class User(BaseModel): first_name: str = Field(validation_alias=AliasChoices('first_name', 'fname')) last_name: str = Field(validation_alias=AliasChoices('last_name', 'lname')) user = User.model_validate({'fname': 'John', 'lname': 'Doe'}) # (1)! print(user) #> first_name='John' last_name='Doe' user = User.model_validate({'first_name': 'John', 'lname': 'Doe'}) # (2)! print(user) #> first_name='John' last_name='Doe' user = User.model_validate({'first_name': 'John', 'fname': 'J', 'lname': 'Doe'}) # (3)! print(user) #> first_name='John' last_name='Doe' ``` 1. We are using the second alias choice for both fields. 2. We are using the first alias choice for the field `'first_name'` and the second alias choice for the field `'last_name'`. 3. Both `'first_name'` and `'fname'` are provided, `'first_name'` is used because it has higher priority. You can also use `AliasChoices` with `AliasPath`: ```python {lint="skip"} from pydantic import BaseModel, Field, AliasPath, AliasChoices class User(BaseModel): first_name: str = Field(validation_alias=AliasChoices('first_name', AliasPath('names', 0))) last_name: str = Field(validation_alias=AliasChoices('last_name', AliasPath('names', 1))) user = User.model_validate({'first_name': 'John', 'last_name': 'Doe'}) print(user) #> first_name='John' last_name='Doe' user = User.model_validate({'names': ['John', 'Doe']}) print(user) #> first_name='John' last_name='Doe' user = User.model_validate({'names': ['John'], 'last_name': 'Doe'}) print(user) #> first_name='John' last_name='Doe' ``` ## Using alias generators You can use the `alias_generator` parameter of [`Config`][pydantic.config.ConfigDict.alias_generator] to specify a callable (or group of callables, via `AliasGenerator`) that will generate aliases for all fields in a model. This is useful if you want to use a consistent naming convention for all fields in a model, but do not want to specify the alias for each field individually. !!! note Pydantic offers three built-in alias generators that you can use out of the box: [`to_pascal`][pydantic.alias_generators.to_pascal]
[`to_camel`][pydantic.alias_generators.to_camel]
[`to_snake`][pydantic.alias_generators.to_snake]
### Using a callable Here's a basic example using a callable: ```python from pydantic import BaseModel, ConfigDict class Tree(BaseModel): model_config = ConfigDict( alias_generator=lambda field_name: field_name.upper() ) age: int height: float kind: str t = Tree.model_validate({'AGE': 12, 'HEIGHT': 1.2, 'KIND': 'oak'}) print(t.model_dump(by_alias=True)) #> {'AGE': 12, 'HEIGHT': 1.2, 'KIND': 'oak'} ``` ### Using an `AliasGenerator` ??? api "API Documentation" [`pydantic.aliases.AliasGenerator`][pydantic.aliases.AliasGenerator]
`AliasGenerator` is a class that allows you to specify multiple alias generators for a model. You can use an `AliasGenerator` to specify different alias generators for validation and serialization. This is particularly useful if you need to use different naming conventions for loading and saving data, but you don't want to specify the validation and serialization aliases for each field individually. For example: ```python from pydantic import AliasGenerator, BaseModel, ConfigDict class Tree(BaseModel): model_config = ConfigDict( alias_generator=AliasGenerator( validation_alias=lambda field_name: field_name.upper(), serialization_alias=lambda field_name: field_name.title(), ) ) age: int height: float kind: str t = Tree.model_validate({'AGE': 12, 'HEIGHT': 1.2, 'KIND': 'oak'}) print(t.model_dump(by_alias=True)) #> {'Age': 12, 'Height': 1.2, 'Kind': 'oak'} ``` ## Alias Precedence If you specify an `alias` on the [`Field`][pydantic.fields.Field], it will take precedence over the generated alias by default: ```python from pydantic import BaseModel, ConfigDict, Field def to_camel(string: str) -> str: return ''.join(word.capitalize() for word in string.split('_')) class Voice(BaseModel): model_config = ConfigDict(alias_generator=to_camel) name: str language_code: str = Field(alias='lang') voice = Voice(Name='Filiz', lang='tr-TR') print(voice.language_code) #> tr-TR print(voice.model_dump(by_alias=True)) #> {'Name': 'Filiz', 'lang': 'tr-TR'} ``` ### Alias Priority You may set `alias_priority` on a field to change this behavior: * `alias_priority=2` the alias will *not* be overridden by the alias generator. * `alias_priority=1` the alias *will* be overridden by the alias generator. * `alias_priority` not set: * alias is set: the alias will *not* be overridden by the alias generator. * alias is not set: the alias *will* be overridden by the alias generator. The same precedence applies to `validation_alias` and `serialization_alias`. See more about the different field aliases under [field aliases](../concepts/fields.md#field-aliases). ## Alias Configuration You can use [`ConfigDict`](./config.md) settings or runtime validation/serialization settings to control whether or not aliases are used. ### `ConfigDict` Settings You can use [configuration settings](./config.md) to control, at the model level, whether or not aliases are used for validation and serialization. If you would like to control this behavior for nested models/surpassing the config-model boundary, use [runtime settings](#runtime-settings). #### Validation When validating data, you can enable population of attributes by attribute name, alias, or both. **By default**, Pydantic uses aliases for validation. Further configuration is available via: * [`ConfigDict.validate_by_alias`][pydantic.config.ConfigDict.validate_by_alias]: `True` by default * [`ConfigDict.validate_by_name`][pydantic.config.ConfigDict.validate_by_name]: `False` by default === "`validate_by_alias`" ```python from pydantic import BaseModel, ConfigDict, Field class Model(BaseModel): my_field: str = Field(validation_alias='my_alias') model_config = ConfigDict(validate_by_alias=True, validate_by_name=False) print(repr(Model(my_alias='foo'))) # (1)! #> Model(my_field='foo') ``` 1. The alias `my_alias` is used for validation. === "`validate_by_name`" ```python from pydantic import BaseModel, ConfigDict, Field class Model(BaseModel): my_field: str = Field(validation_alias='my_alias') model_config = ConfigDict(validate_by_alias=False, validate_by_name=True) print(repr(Model(my_field='foo'))) # (1)! #> Model(my_field='foo') ``` 1. the attribute identifier `my_field` is used for validation. === "`validate_by_alias` and `validate_by_name`" ```python from pydantic import BaseModel, ConfigDict, Field class Model(BaseModel): my_field: str = Field(validation_alias='my_alias') model_config = ConfigDict(validate_by_alias=True, validate_by_name=True) print(repr(Model(my_alias='foo'))) # (1)! #> Model(my_field='foo') print(repr(Model(my_field='foo'))) # (2)! #> Model(my_field='foo') ``` 1. The alias `my_alias` is used for validation. 2. the attribute identifier `my_field` is used for validation. !!! warning You cannot set both `validate_by_alias` and `validate_by_name` to `False`. A [user error](../errors/usage_errors.md#validate-by-alias-and-name-false) is raised in this case. #### Serialization When serializing data, you can enable serialization by alias, which is disabled by default. See the [`ConfigDict.serialize_by_alias`][pydantic.config.ConfigDict.serialize_by_alias] API documentation for more details. ```python from pydantic import BaseModel, ConfigDict, Field class Model(BaseModel): my_field: str = Field(serialization_alias='my_alias') model_config = ConfigDict(serialize_by_alias=True) m = Model(my_field='foo') print(m.model_dump()) # (1)! #> {'my_alias': 'foo'} ``` 1. The alias `my_alias` is used for serialization. !!! note The fact that serialization by alias is disabled by default is notably inconsistent with the default for validation (where aliases are used by default). We anticipate changing this default in V3. ### Runtime Settings You can use runtime alias flags to control alias use for validation and serialization on a per-call basis. If you would like to control this behavior on a model level, use [`ConfigDict` settings](#configdict-settings). #### Validation When validating data, you can enable population of attributes by attribute name, alias, or both. The `by_alias` and `by_name` flags are available on the [`model_validate()`][pydantic.main.BaseModel.model_validate], [`model_validate_json()`][pydantic.main.BaseModel.model_validate_json], and [`model_validate_strings()`][pydantic.main.BaseModel.model_validate_strings] methods, as well as the [`TypeAdapter`][pydantic.type_adapter.TypeAdapter] validation methods. By default: * `by_alias` is `True` * `by_name` is `False` === "`by_alias`" ```python from pydantic import BaseModel, Field class Model(BaseModel): my_field: str = Field(validation_alias='my_alias') m = Model.model_validate( {'my_alias': 'foo'}, # (1)! by_alias=True, by_name=False, ) print(repr(m)) #> Model(my_field='foo') ``` 1. The alias `my_alias` is used for validation. === "`by_name`" ```python from pydantic import BaseModel, Field class Model(BaseModel): my_field: str = Field(validation_alias='my_alias') m = Model.model_validate( {'my_field': 'foo'}, by_alias=False, by_name=True # (1)! ) print(repr(m)) #> Model(my_field='foo') ``` 1. The attribute name `my_field` is used for validation. === "`validate_by_alias` and `validate_by_name`" ```python from pydantic import BaseModel, Field class Model(BaseModel): my_field: str = Field(validation_alias='my_alias') m = Model.model_validate( {'my_alias': 'foo'}, by_alias=True, by_name=True # (1)! ) print(repr(m)) #> Model(my_field='foo') m = Model.model_validate( {'my_field': 'foo'}, by_alias=True, by_name=True # (2)! ) print(repr(m)) #> Model(my_field='foo') ``` 1. The alias `my_alias` is used for validation. 2. The attribute name `my_field` is used for validation. !!! warning You cannot set both `by_alias` and `by_name` to `False`. A [user error](../errors/usage_errors.md#validate-by-alias-and-name-false) is raised in this case. #### Serialization When serializing data, you can enable serialization by alias via the `by_alias` flag which is available on the [`model_dump()`][pydantic.main.BaseModel.model_dump] and [`model_dump_json()`][pydantic.main.BaseModel.model_dump_json] methods, as well as the [`TypeAdapter`][pydantic.type_adapter.TypeAdapter] ones. By default, `by_alias` is `False`. ```py from pydantic import BaseModel, Field class Model(BaseModel): my_field: str = Field(serialization_alias='my_alias') m = Model(my_field='foo') print(m.model_dump(by_alias=True)) # (1)! #> {'my_alias': 'foo'} ``` 1. The alias `my_alias` is used for serialization. !!! note The fact that serialization by alias is disabled by default is notably inconsistent with the default for validation (where aliases are used by default). We anticipate changing this default in V3. pydantic-pydantic-ba0aa01/docs/concepts/config.md000066400000000000000000000142121517143232300221430ustar00rootroot00000000000000The behaviour of Pydantic can be controlled via a variety of configuration values, documented on the [`ConfigDict`][pydantic.ConfigDict] class. This page describes how configuration can be specified for Pydantic's supported types. ## Configuration on Pydantic models On Pydantic models, configuration can be specified in two ways: * Using the [`model_config`][pydantic.BaseModel.model_config] class attribute: ```python from pydantic import BaseModel, ConfigDict, ValidationError class Model(BaseModel): model_config = ConfigDict(str_max_length=5) # (1)! v: str try: m = Model(v='abcdef') except ValidationError as e: print(e) """ 1 validation error for Model v String should have at most 5 characters [type=string_too_long, input_value='abcdef', input_type=str] """ ``` 1. A plain dictionary (i.e. `{'str_max_length': 5}`) can also be used. !!! note In Pydantic V1, the `Config` class was used. This is still supported, but **deprecated**. * Using class arguments: ```python from pydantic import BaseModel class Model(BaseModel, frozen=True): a: str ``` Unlike the [`model_config`][pydantic.BaseModel.model_config] class attribute, static type checkers will recognize class arguments. For `frozen`, any instance mutation will be flagged as an type checking error. ## Configuration on Pydantic dataclasses [Pydantic dataclasses](./dataclasses.md) also support configuration (read more in the [dedicated section](./dataclasses.md#dataclass-config)). ```python from pydantic import ConfigDict, ValidationError from pydantic.dataclasses import dataclass @dataclass(config=ConfigDict(str_max_length=10, validate_assignment=True)) class User: name: str user = User(name='John Doe') try: user.name = 'x' * 20 except ValidationError as e: print(e) """ 1 validation error for User name String should have at most 10 characters [type=string_too_long, input_value='xxxxxxxxxxxxxxxxxxxx', input_type=str] """ ``` ## Configuration on `TypeAdapter` [Type adapters](./type_adapter.md) (using the [`TypeAdapter`][pydantic.TypeAdapter] class) support configuration, by providing the `config` argument. ```python from pydantic import ConfigDict, TypeAdapter ta = TypeAdapter(list[str], config=ConfigDict(coerce_numbers_to_str=True)) print(ta.validate_python([1, 2])) #> ['1', '2'] ``` Configuration can't be provided if the type adapter directly wraps a type that support it, and a [usage error](../errors/usage_errors.md) is raised in this case. The [configuration propagation](#configuration-propagation) rules also apply. ## Configuration on other supported types If you are using [standard library dataclasses][dataclasses] or [`TypedDict`][typing.TypedDict] classes, the configuration can be set in two ways: * Using the `__pydantic_config__` class attribute: ```python from dataclasses import dataclass from pydantic import ConfigDict @dataclass class User: __pydantic_config__ = ConfigDict(strict=True) id: int name: str = 'John Doe' ``` * Using the [`@with_config`][pydantic.config.with_config] decorator (this avoids static type checking errors with [`TypedDict`][typing.TypedDict]): ```python from typing_extensions import TypedDict from pydantic import ConfigDict, with_config @with_config(ConfigDict(str_to_lower=True)) class Model(TypedDict): x: str ``` ## Configuration on the `@validate_call` decorator The [`@validate_call`](./validation_decorator.md) also supports setting custom configuration. See the [dedicated section](./validation_decorator.md#custom-configuration) for more details. ## Change behaviour globally If you wish to change the behaviour of Pydantic globally, you can create your own custom parent class with a custom configuration, as the configuration is inherited: ```python from pydantic import BaseModel, ConfigDict class Parent(BaseModel): model_config = ConfigDict(extra='allow') class Model(Parent): x: str m = Model(x='foo', y='bar') print(m.model_dump()) #> {'x': 'foo', 'y': 'bar'} ``` If you provide configuration to the subclasses, it will be *merged* with the parent configuration: ```python from pydantic import BaseModel, ConfigDict class Parent(BaseModel): model_config = ConfigDict(extra='allow', str_to_lower=False) class Model(Parent): model_config = ConfigDict(str_to_lower=True) x: str m = Model(x='FOO', y='bar') print(m.model_dump()) #> {'x': 'foo', 'y': 'bar'} print(Model.model_config) #> {'extra': 'allow', 'str_to_lower': True} ``` !!! warning If your model inherits from multiple bases, Pydantic currently *doesn't* follow the [MRO]. For more details, see [this issue](https://github.com/pydantic/pydantic/issues/9992). [MRO]: https://docs.python.org/3/glossary.html#term-method-resolution-order ## Configuration propagation When using types that support configuration as field annotations, configuration may not be propagated: * For Pydantic models and dataclasses, configuration will *not* be propagated, each model has its own "configuration boundary": ```python from pydantic import BaseModel, ConfigDict class User(BaseModel): name: str class Parent(BaseModel): user: User model_config = ConfigDict(str_to_lower=True) print(Parent(user={'name': 'JOHN'})) #> user=User(name='JOHN') ``` * For stdlib types (dataclasses and typed dictionaries), configuration will be propagated, unless the type has its own configuration set: ```python from dataclasses import dataclass from pydantic import BaseModel, ConfigDict, with_config @dataclass class UserWithoutConfig: name: str @dataclass @with_config(str_to_lower=False) class UserWithConfig: name: str class Parent(BaseModel): user_1: UserWithoutConfig user_2: UserWithConfig model_config = ConfigDict(str_to_lower=True) print(Parent(user_1={'name': 'JOHN'}, user_2={'name': 'JOHN'})) #> user_1=UserWithoutConfig(name='john') user_2=UserWithConfig(name='JOHN') ``` pydantic-pydantic-ba0aa01/docs/concepts/conversion_table.md000066400000000000000000000007421517143232300242350ustar00rootroot00000000000000The following table provides details on how Pydantic converts data during validation in both strict and lax modes. The "Strict" column contains checkmarks for type conversions that are allowed when validating in [Strict Mode](strict_mode.md). === "All" {{ conversion_table_all }} === "JSON" {{ conversion_table_json }} === "JSON - Strict" {{ conversion_table_json_strict }} === "Python" {{ conversion_table_python }} === "Python - Strict" {{ conversion_table_python_strict }} pydantic-pydantic-ba0aa01/docs/concepts/dataclasses.md000066400000000000000000000310241517143232300231650ustar00rootroot00000000000000??? api "API Documentation" [`@pydantic.dataclasses.dataclass`][pydantic.dataclasses.dataclass]
If you don't want to use Pydantic's [`BaseModel`][pydantic.BaseModel] you can instead get the same data validation on standard [dataclasses][dataclasses]. ```python from datetime import datetime from typing import Optional from pydantic.dataclasses import dataclass @dataclass class User: id: int name: str = 'John Doe' signup_ts: Optional[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)) """ ``` !!! note Keep in mind that Pydantic dataclasses are **not** a replacement for [Pydantic models](../concepts/models.md). They provide a similar functionality to stdlib dataclasses with the addition of Pydantic validation. There are cases where using Pydantic models is the better choice. For more information and discussion see [pydantic/pydantic#710](https://github.com/pydantic/pydantic/issues/710). Similarities between Pydantic dataclasses and models include support for: * [Configuration](#dataclass-config) support (note that dataclasses doesn't support the `model_config` attribute as with Pydantic models) * [Nested](./models.md#nested-models) classes * Arguments used to instantiate the dataclass are also [copied](./models.md#attribute-copies). Some differences between Pydantic dataclasses and models include: * The [various methods](./models.md#model-methods-and-properties) to validate, dump and generate a JSON Schema aren't available. Instead, you can wrap the dataclass with a [`TypeAdapter`][pydantic.type_adapter.TypeAdapter] and make use of its methods: ```python from pydantic import TypeAdapter from pydantic.dataclasses import dataclass @dataclass class Foo: f: int foo = Foo(f=1) TypeAdapter(Foo).dump_python(foo) #> {'f': 1} TypeAdapter(Foo).validate_python({'f': 1}) #> Foo(f=1) ``` * Validators (see the [dedicated section](#validators-and-initialization-hooks)). * The [`extra`][pydantic.ConfigDict.extra] configuration behavior: * Extra data is not included in [serialization](./serialization.md#serializing-data). * There is no way to customize validation of extra values [using the `__pydantic_extra__` attribute](./models.md#extra-data). * Generic dataclasses are supported, but as with other standard library generic types, using a parameterized dataclass won't work as expected: === "Python 3.9 and above" ```python {upgrade="skip"} from typing import Generic, TypeVar from pydantic.dataclasses import dataclass T = TypeVar('T') @dataclass class Foo(Generic[T]): f: T Foo[int](f='not_an_int') # (1)! #> Foo(f='not_an_int') ``` 1. Unlike [generic Pydantic models](./models.md#generic-models), `Foo[int]` is a [generic alias][types-genericalias] and not a proper type object. As such, Pydantic currently treats `Foo[int]` the same as `Foo[Any]`, without performing validation for `f`. === "Python 3.12 and above (new syntax)" ```python {requires="3.12" upgrade="skip" lint="skip"} from pydantic.dataclasses import dataclass @dataclass class Foo[T]: f: T Foo[int](f='not_an_int') # (1)! #> Foo(f='not_an_int') ``` 1. Unlike [generic Pydantic models](./models.md#generic-models), `Foo[int]` is a [generic alias][types-genericalias] and not a proper type object. As such, Pydantic currently performs no validation. Instead, you can wrap the `Foo[int]` parameterized class with a [`TypeAdapter`][pydantic.type_adapter.TypeAdapter]. You can use both the Pydantic's [`Field()`][pydantic.Field] and the stdlib's [`field()`][dataclasses.field] functions: ```python import dataclasses from typing import Optional from pydantic import Field from pydantic.dataclasses import dataclass @dataclass class User: id: int name: str = 'John Doe' friends: list[int] = dataclasses.field(default_factory=lambda: [0]) age: Optional[int] = dataclasses.field( default=None, metadata={'title': 'The age of the user', 'description': 'do not lie!'}, ) height: Optional[int] = Field( default=None, title='The height in cm', ge=50, le=300 ) user = User(id='42', height='250') print(user) #> User(id=42, name='John Doe', friends=[0], age=None, height=250) ``` The Pydantic [`@dataclass`][pydantic.dataclasses.dataclass] decorator accepts the same arguments as the standard decorator, with the addition of a `config` parameter. ## Dataclass config If you want to modify the configuration like you would with a [`BaseModel`][pydantic.BaseModel], you have two options: * Use the `config` parameter of the decorator. * Define the configuration with the `__pydantic_config__` attribute. ```python from pydantic import ConfigDict from pydantic.dataclasses import dataclass # Option 1 -- using the decorator argument: @dataclass(config=ConfigDict(validate_assignment=True)) # (1)! class MyDataclass1: a: int # Option 2 -- using an attribute: @dataclass class MyDataclass2: a: int __pydantic_config__ = ConfigDict(validate_assignment=True) ``` 1. You can read more about `validate_assignment` in the [API reference][pydantic.config.ConfigDict.validate_assignment]. ## Rebuilding dataclass schema The [`rebuild_dataclass()`][pydantic.dataclasses.rebuild_dataclass] function can be used to rebuild the core schema of the dataclass. See the [rebuilding model schema](./models.md#rebuilding-model-schema) section for more details. ## Stdlib dataclasses and Pydantic dataclasses ### Inherit from stdlib dataclasses Stdlib dataclasses (nested or not) can also be inherited and Pydantic will automatically validate all the inherited fields. ```python import dataclasses import pydantic @dataclasses.dataclass class Z: z: int @dataclasses.dataclass class Y(Z): y: int = 0 @pydantic.dataclasses.dataclass class X(Y): x: int = 0 foo = X(x=b'1', y='2', z='3') print(foo) #> X(z=3, y=2, x=1) try: X(z='pika') except pydantic.ValidationError as e: print(e) """ 1 validation error for X z Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='pika', input_type=str] """ ``` The decorator can also be applied directly on a stdlib dataclass, in which case a new subclass will be created: ```python import dataclasses import pydantic @dataclasses.dataclass class A: a: int PydanticA = pydantic.dataclasses.dataclass(A) print(PydanticA(a='1')) #> A(a=1) ``` ### Usage of stdlib dataclasses with `BaseModel` When a standard library dataclass is used within a Pydantic model, a Pydantic dataclass or a [`TypeAdapter`][pydantic.TypeAdapter], validation will be applied (and the [configuration](#dataclass-config) stays the same). This means that using a stdlib or a Pydantic dataclass as a field annotation is functionally equivalent. ```python import dataclasses from typing import Optional from pydantic import BaseModel, ConfigDict, ValidationError @dataclasses.dataclass(frozen=True) class User: name: str class Foo(BaseModel): # Required so that pydantic revalidates the model attributes: model_config = ConfigDict(revalidate_instances='always') user: Optional[User] = None # nothing is validated as expected: user = User(name=['not', 'a', 'string']) print(user) #> User(name=['not', 'a', 'string']) try: Foo(user=user) except ValidationError as e: print(e) """ 1 validation error for Foo user.name Input should be a valid string [type=string_type, input_value=['not', 'a', 'string'], input_type=list] """ foo = Foo(user=User(name='pika')) try: foo.user.name = 'bulbi' except dataclasses.FrozenInstanceError as e: print(e) #> cannot assign to field 'name' ``` ### Using custom types As said above, validation is applied on standard library dataclasses. If you make use of custom types, you will get an error when trying to refer to the dataclass. To circumvent the issue, you can set the [`arbitrary_types_allowed`][pydantic.ConfigDict.arbitrary_types_allowed] configuration value on the dataclass: ```python import dataclasses from pydantic import BaseModel, ConfigDict from pydantic.errors import PydanticSchemaGenerationError class ArbitraryType: def __init__(self, value): self.value = value def __repr__(self): return f'ArbitraryType(value={self.value!r})' @dataclasses.dataclass class DC: a: ArbitraryType b: str # valid as it is a stdlib dataclass without validation: my_dc = DC(a=ArbitraryType(value=3), b='qwe') try: class Model(BaseModel): dc: DC other: str # invalid as dc is now validated with pydantic, and ArbitraryType is not a known type Model(dc=my_dc, other='other') except PydanticSchemaGenerationError as e: print(e.message) """ Unable to generate pydantic-core schema for . Set `arbitrary_types_allowed=True` in the model_config to ignore this error or implement `__get_pydantic_core_schema__` on your type to fully support it. If you got this error by calling handler() within `__get_pydantic_core_schema__` then you likely need to call `handler.generate_schema()` since we do not call `__get_pydantic_core_schema__` on `` otherwise to avoid infinite recursion. """ # valid as we set arbitrary_types_allowed=True, and that config pushes down to the nested vanilla dataclass class Model(BaseModel): model_config = ConfigDict(arbitrary_types_allowed=True) dc: DC other: str m = Model(dc=my_dc, other='other') print(repr(m)) #> Model(dc=DC(a=ArbitraryType(value=3), b='qwe'), other='other') ``` ### Checking if a dataclass is a Pydantic dataclass Pydantic dataclasses are still considered dataclasses, so using [`dataclasses.is_dataclass()`][dataclasses.is_dataclass] will return `True`. To check if a type is specifically a Pydantic dataclass you can use the [`is_pydantic_dataclass()`][pydantic.dataclasses.is_pydantic_dataclass] function. ```python import dataclasses import pydantic @dataclasses.dataclass class StdLibDataclass: id: int PydanticDataclass = pydantic.dataclasses.dataclass(StdLibDataclass) print(dataclasses.is_dataclass(StdLibDataclass)) #> True print(pydantic.dataclasses.is_pydantic_dataclass(StdLibDataclass)) #> False print(dataclasses.is_dataclass(PydanticDataclass)) #> True print(pydantic.dataclasses.is_pydantic_dataclass(PydanticDataclass)) #> True ``` ## Validators and initialization hooks Validators also work with Pydantic dataclasses: ```python from pydantic import field_validator from pydantic.dataclasses import dataclass @dataclass class DemoDataclass: product_id: str # should be a five-digit string, may have leading zeros @field_validator('product_id', mode='before') @classmethod def convert_int_serial(cls, v): if isinstance(v, int): v = str(v).zfill(5) return v print(DemoDataclass(product_id='01234')) #> DemoDataclass(product_id='01234') print(DemoDataclass(product_id=2468)) #> DemoDataclass(product_id='02468') ``` The dataclass [`__post_init__()`][dataclasses.__post_init__] method is also supported, and will be called between the calls to *before* and *after* model validators. ??? example ```python from pydantic_core import ArgsKwargs from typing_extensions import Self from pydantic import model_validator from pydantic.dataclasses import dataclass @dataclass class Birth: year: int month: int day: int @dataclass class User: birth: Birth @model_validator(mode='before') @classmethod def before(cls, values: ArgsKwargs) -> ArgsKwargs: print(f'First: {values}') # (1)! """ First: ArgsKwargs((), {'birth': {'year': 1995, 'month': 3, 'day': 2}}) """ return values @model_validator(mode='after') def after(self) -> Self: print(f'Third: {self}') #> Third: User(birth=Birth(year=1995, month=3, day=2)) return self def __post_init__(self): print(f'Second: {self.birth}') #> Second: Birth(year=1995, month=3, day=2) user = User(**{'birth': {'year': 1995, 'month': 3, 'day': 2}}) ``` 1. Unlike Pydantic models, the `values` parameter is of type [`ArgsKwargs`][pydantic_core.ArgsKwargs] pydantic-pydantic-ba0aa01/docs/concepts/experimental.md000066400000000000000000000502771517143232300234060ustar00rootroot00000000000000# Experimental Features In this section you will find documentation for new, experimental features in Pydantic. These features are subject to change or removal, and we are looking for feedback and suggestions before making them a permanent part of Pydantic. See our [Version Policy](../version-policy.md#experimental-features) for more information on experimental features. ## Feedback We welcome feedback on experimental features! Please open an issue on the [Pydantic GitHub repository](https://github.com/pydantic/pydantic/issues/new/choose) to share your thoughts, requests, or suggestions. We also encourage you to read through existing feedback and add your thoughts to existing issues. ## Pipeline API Pydantic v2.8.0 introduced an experimental "pipeline" API that allows composing of parsing (validation), constraints and transformations in a more type-safe manner than existing APIs. This API is subject to change or removal, we are looking for feedback and suggestions before making it a permanent part of Pydantic. ??? api "API Documentation" [`pydantic.experimental.pipeline`][pydantic.experimental.pipeline]
Generally, the pipeline API is used to define a sequence of steps to apply to incoming data during validation. The pipeline API is designed to be more type-safe and composable than the existing Pydantic API. Each step in the pipeline can be: * A validation step that runs pydantic validation on the provided type * A transformation step that modifies the data * A constraint step that checks the data against a condition * A predicate step that checks the data against a condition and raises an error if it returns `False` Note that the following example attempts to be exhaustive at the cost of complexity: if you find yourself writing this many transformations in type annotations you may want to consider having a `UserIn` and `UserOut` model (example below) or similar where you make the transformations via idiomatic plain Python code. These APIs are meant for situations where the code savings are significant and the added complexity is relatively small. ```python from __future__ import annotations from datetime import datetime from typing import Annotated from pydantic import BaseModel from pydantic.experimental.pipeline import validate_as class User(BaseModel): name: Annotated[str, validate_as(str).str_lower()] # (1)! age: Annotated[int, validate_as(int).gt(0)] # (2)! username: Annotated[str, validate_as(str).str_pattern(r'[a-z]+')] # (3)! password: Annotated[ str, validate_as(str) .transform(str.lower) .predicate(lambda x: x != 'password'), # (4)! ] favorite_number: Annotated[ # (5)! int, (validate_as(int) | validate_as(str).str_strip().validate_as(int)).gt( 0 ), ] friends: Annotated[list[User], validate_as(...).len(0, 100)] # (6)! bio: Annotated[ datetime, validate_as(int) .transform(lambda x: x / 1_000_000) .validate_as(...), # (8)! ] ``` 1. Lowercase a string. 2. Constrain an integer to be greater than zero. 3. Constrain a string to match a regex pattern. 4. You can also use the lower level transform, constrain and predicate methods. 5. Use the `|` or `&` operators to combine steps (like a logical OR or AND). 6. Calling `validate_as(...)` with `Ellipsis`, `...` as the first positional argument implies `validate_as()`. Use `validate_as(Any)` to accept any type. 7. You can call `validate_as()` before or after other steps to do pre or post processing. ### Mapping from `BeforeValidator`, `AfterValidator` and `WrapValidator` The `validate_as` method is a more type-safe way to define `BeforeValidator`, `AfterValidator` and `WrapValidator`: ```python from typing import Annotated from pydantic.experimental.pipeline import transform, validate_as # BeforeValidator Annotated[int, validate_as(str).str_strip().validate_as(...)] # (1)! # AfterValidator Annotated[int, transform(lambda x: x * 2)] # (2)! # WrapValidator Annotated[ int, validate_as(str) .str_strip() .validate_as(...) .transform(lambda x: x * 2), # (3)! ] ``` 1. Strip whitespace from a string before parsing it as an integer. 2. Multiply an integer by 2 after parsing it. 3. Strip whitespace from a string, validate it as an integer, then multiply it by 2. ### Alternative patterns There are many alternative patterns to use depending on the scenario. Just as an example, consider the `UserIn` and `UserOut` pattern mentioned above: ```python from __future__ import annotations from pydantic import BaseModel class UserIn(BaseModel): favorite_number: int | str class UserOut(BaseModel): favorite_number: int def my_api(user: UserIn) -> UserOut: favorite_number = user.favorite_number if isinstance(favorite_number, str): favorite_number = int(user.favorite_number.strip()) return UserOut(favorite_number=favorite_number) assert my_api(UserIn(favorite_number=' 1 ')).favorite_number == 1 ``` This example uses plain idiomatic Python code that may be easier to understand, type-check, etc. than the examples above. The approach you choose should really depend on your use case. You will have to compare verbosity, performance, ease of returning meaningful errors to your users, etc. to choose the right pattern. Just be mindful of abusing advanced patterns like the pipeline API just because you can. ## Partial Validation /// version-added | v2.10 /// Partial validation allows you to validate an incomplete JSON string, or a Python object representing incomplete input data. Partial validation is particularly helpful when processing the output of an LLM, where the model streams structured responses, and you may wish to begin validating the stream while you're still receiving data (e.g. to show partial data to users). !!! warning Partial validation is an experimental feature and may change in future versions of Pydantic. The current implementation should be considered a proof of concept at this time and has a number of [limitations](#limitations-of-partial-validation). Partial validation can be enabled when using the three validation methods on `TypeAdapter`: [`TypeAdapter.validate_json()`][pydantic.TypeAdapter.validate_json], [`TypeAdapter.validate_python()`][pydantic.TypeAdapter.validate_python], and [`TypeAdapter.validate_strings()`][pydantic.TypeAdapter.validate_strings]. This allows you to parse and validation incomplete JSON, but also to validate Python objects created by parsing incomplete data of any format. The `experimental_allow_partial` flag can be passed to these methods to enable partial validation. It can take the following values (and is `False`, by default): * `False` or `'off'` - disable partial validation * `True` or `'on'` - enable partial validation, but don't support trailing strings * `'trailing-strings'` - enable partial validation and support trailing strings !!! info "`'trailing-strings'` mode" `'trailing-strings'` mode allows for trailing incomplete strings at the end of partial JSON to be included in the output. For example, if you're validating against the following model: ```python from typing import TypedDict class Model(TypedDict): a: str b: str ``` Then the following JSON input would be considered valid, despite the incomplete string at the end: ```json '{"a": "hello", "b": "wor' ``` And would be validated as: ```python {test="skip" lint="skip"} {'a': 'hello', 'b': 'wor'} ``` `experiment_allow_partial` in action: ```python from typing import Annotated from annotated_types import MinLen from typing_extensions import NotRequired, TypedDict from pydantic import TypeAdapter class Foobar(TypedDict): # (1)! a: int b: NotRequired[float] c: NotRequired[Annotated[str, MinLen(5)]] ta = TypeAdapter(list[Foobar]) v = ta.validate_json('[{"a": 1, "b"', experimental_allow_partial=True) # (2)! print(v) #> [{'a': 1}] v = ta.validate_json( '[{"a": 1, "b": 1.0, "c": "abcd', experimental_allow_partial=True # (3)! ) print(v) #> [{'a': 1, 'b': 1.0}] v = ta.validate_json( '[{"b": 1.0, "c": "abcde"', experimental_allow_partial=True # (4)! ) print(v) #> [] v = ta.validate_json( '[{"a": 1, "b": 1.0, "c": "abcde"},{"a": ', experimental_allow_partial=True ) print(v) #> [{'a': 1, 'b': 1.0, 'c': 'abcde'}] v = ta.validate_python([{'a': 1}], experimental_allow_partial=True) # (5)! print(v) #> [{'a': 1}] v = ta.validate_python( [{'a': 1, 'b': 1.0, 'c': 'abcd'}], experimental_allow_partial=True # (6)! ) print(v) #> [{'a': 1, 'b': 1.0}] v = ta.validate_json( '[{"a": 1, "b": 1.0, "c": "abcdefg', experimental_allow_partial='trailing-strings', # (7)! ) print(v) #> [{'a': 1, 'b': 1.0, 'c': 'abcdefg'}] ``` 1. The TypedDict `Foobar` has three field, but only `a` is required, that means that a valid instance of `Foobar` can be created even if the `b` and `c` fields are missing. 2. Parsing JSON, the input is valid JSON up to the point where the string is truncated. 3. In this case truncation of the input means the value of `c` (`abcd`) is invalid as input to `c` field, hence it's omitted. 4. The `a` field is required, so validation on the only item in the list fails and is dropped. 5. Partial validation also works with Python objects, it should have the same semantics as with JSON except of course you can't have a genuinely "incomplete" Python object. 6. The same as above but with a Python object, `c` is dropped as it's not required and failed validation. 7. The `trailing-strings` mode allows for incomplete strings at the end of partial JSON to be included in the output, in this case the input is valid JSON up to the point where the string is truncated, so the last string is included. ### How Partial Validation Works Partial validation follows the zen of Pydantic — it makes no guarantees about what the input data might have been, but it does guarantee to return a valid instance of the type you required, or raise a validation error. To do this, the `experimental_allow_partial` flag enables two pieces of behavior: #### 1. Partial JSON parsing The [jiter](https://github.com/pydantic/jiter) JSON parser used by Pydantic already supports parsing partial JSON, `experimental_allow_partial` is simply passed to jiter via the `allow_partial` argument. !!! note If you just want pure JSON parsing with support for partial JSON, you can use the [`jiter`](https://pypi.org/project/jiter/) Python library directly, or pass the `allow_partial` argument when calling [`pydantic_core.from_json`][pydantic_core.from_json]. #### 2. Ignore errors in the last element of the input {#2-ignore-errors-in-last} Only having access to part of the input data means errors can commonly occur in the last element of the input data. For example: * if a string has a constraint `MinLen(5)`, when you only see part of the input, validation might fail because part of the string is missing (e.g. `{"name": "Sam` instead of `{"name": "Samuel"}`) * if an `int` field has a constraint `Ge(10)`, when you only see part of the input, validation might fail because the number is too small (e.g. `1` instead of `10`) * if a `TypedDict` field has 3 required fields, but the partial input only has two of the fields, validation would fail because some field are missing * etc. etc. — there are lost more cases like this The point is that if you only see part of some valid input data, validation errors can often occur in the last element of a sequence or last value of mapping. To avoid these errors breaking partial validation, Pydantic will ignore ALL errors in the last element of the input data. ```python {title="Errors in last element ignored"} from typing import Annotated from annotated_types import MinLen from pydantic import BaseModel, TypeAdapter class MyModel(BaseModel): a: int b: Annotated[str, MinLen(5)] ta = TypeAdapter(list[MyModel]) v = ta.validate_json( '[{"a": 1, "b": "12345"}, {"a": 1,', experimental_allow_partial=True, ) print(v) #> [MyModel(a=1, b='12345')] ``` ### Limitations of Partial Validation #### TypeAdapter only You can only pass `experiment_allow_partial` to [`TypeAdapter`][pydantic.TypeAdapter] methods, it's not yet supported via other Pydantic entry points like [`BaseModel`][pydantic.BaseModel]. #### Types supported Right now only a subset of collection validators know how to handle partial validation: * `list` * `set` * `frozenset` * `dict` (as in `dict[X, Y]`) * `TypedDict` — only non-required fields may be missing, e.g. via [`NotRequired`][typing.NotRequired] or [`total=False`][typing.TypedDict.__total__]) While you can use `experimental_allow_partial` while validating against types that include other collection validators, those types will be validated "all or nothing", and partial validation will not work on more nested types. E.g. in the [above](#2-ignore-errors-in-last) example partial validation works although the second item in the list is dropped completely since `BaseModel` doesn't (yet) support partial validation. But partial validation won't work at all in the follow example because `BaseModel` doesn't support partial validation so it doesn't forward the `allow_partial` instruction down to the list validator in `b`: ```python from typing import Annotated from annotated_types import MinLen from pydantic import BaseModel, TypeAdapter, ValidationError class MyModel(BaseModel): a: int = 1 b: list[Annotated[str, MinLen(5)]] = [] # (1)! ta = TypeAdapter(MyModel) try: v = ta.validate_json( '{"a": 1, "b": ["12345", "12', experimental_allow_partial=True ) except ValidationError as e: print(e) """ 1 validation error for MyModel b.1 String should have at least 5 characters [type=string_too_short, input_value='12', input_type=str] """ ``` 1. The list validator for `b` doesn't get the `allow_partial` instruction passed down to it by the model validator so it doesn't know to ignore errors in the last element of the input. #### Some invalid but complete JSON will be accepted The way [jiter](https://github.com/pydantic/jiter) (the JSON parser used by Pydantic) works means it's currently not possible to differentiate between complete JSON like `{"a": 1, "b": "12"}` and incomplete JSON like `{"a": 1, "b": "12`. This means that some invalid JSON will be accepted by Pydantic when using `experimental_allow_partial`, e.g.: ```python from typing import Annotated from annotated_types import MinLen from typing_extensions import TypedDict from pydantic import TypeAdapter class Foobar(TypedDict, total=False): a: int b: Annotated[str, MinLen(5)] ta = TypeAdapter(Foobar) v = ta.validate_json( '{"a": 1, "b": "12', experimental_allow_partial=True # (1)! ) print(v) #> {'a': 1} v = ta.validate_json( '{"a": 1, "b": "12"}', experimental_allow_partial=True # (2)! ) print(v) #> {'a': 1} ``` 1. This will pass validation as expected although the last field will be omitted as it failed validation. 2. This will also pass validation since the binary representation of the JSON data passed to pydantic-core is indistinguishable from the previous case. #### Any error in the last field of the input will be ignored As described [above](#2-ignore-errors-in-last), many errors can result from truncating the input. Rather than trying to specifically ignore errors that could result from truncation, Pydantic ignores all errors in the last element of the input in partial validation mode. This means clearly invalid data will pass validation if the error is in the last field of the input: ```python from typing import Annotated from annotated_types import Ge from pydantic import TypeAdapter ta = TypeAdapter(list[Annotated[int, Ge(10)]]) v = ta.validate_python([20, 30, 4], experimental_allow_partial=True) # (1)! print(v) #> [20, 30] ta = TypeAdapter(list[int]) v = ta.validate_python([1, 2, 'wrong'], experimental_allow_partial=True) # (2)! print(v) #> [1, 2] ``` 1. As you would expect, this will pass validation since Pydantic correctly ignores the error in the (truncated) last item. 2. This will also pass validation since the error in the last item is ignored. ## Validation of a callable's arguments Pydantic provides the [`@validate_call`][pydantic.validate_call] decorator to perform validation on the provided arguments (and additionally return type) of a callable. However, it only allows arguments to be provided by actually calling the decorated callable. In some situations, you may want to just *validate* the arguments, such as when loading from other data sources such as JSON data. For this reason, the experimental [`generate_arguments_schema()`][pydantic.experimental.arguments_schema.generate_arguments_schema] function can be used to construct a core schema, which can later be used with a [`SchemaValidator`][pydantic_core.SchemaValidator]. ```python from pydantic_core import SchemaValidator from pydantic.experimental.arguments_schema import generate_arguments_schema def func(p: bool, *args: str, **kwargs: int) -> None: ... arguments_schema = generate_arguments_schema(func=func) val = SchemaValidator(arguments_schema, config={'coerce_numbers_to_str': True}) args, kwargs = val.validate_json( '{"p": true, "args": ["arg1", 1], "kwargs": {"extra": 1}}' ) print(args, kwargs) # (1)! #> (True, 'arg1', '1') {'extra': 1} ``` 1. If you want the validated arguments as a dictionary, you can use the [`Signature.bind()`][inspect.Signature.bind] method: ```python {test="skip" lint="skip"} from inspect import signature signature(func).bind(*args, **kwargs).arguments #> {'p': True, 'args': ('arg1', '1'), 'kwargs': {'extra': 1}} ``` !!! note Unlike [`@validate_call`][pydantic.validate_call], this core schema will only validate the provided arguments; the underlying callable will *not* be called. Additionally, you can ignore specific parameters by providing a callback, which is called for every parameter: ```python from typing import Any from pydantic_core import SchemaValidator from pydantic.experimental.arguments_schema import generate_arguments_schema def func(p: bool, *args: str, **kwargs: int) -> None: ... def skip_first_parameter(index: int, name: str, annotation: Any) -> Any: if index == 0: return 'skip' arguments_schema = generate_arguments_schema( func=func, parameters_callback=skip_first_parameter, ) val = SchemaValidator(arguments_schema) args, kwargs = val.validate_json('{"args": ["arg1"], "kwargs": {"extra": 1}}') print(args, kwargs) #> ('arg1',) {'extra': 1} ``` ## `MISSING` sentinel The `MISSING` sentinel is a singleton indicating a field value was not provided during validation. This singleton can be used as a default value, as an alternative to `None` when it has an explicit meaning. During serialization, any field with `MISSING` as a value is excluded from the output. ```python from typing import Union from pydantic import BaseModel from pydantic.experimental.missing_sentinel import MISSING class Configuration(BaseModel): timeout: Union[int, None, MISSING] = MISSING # configuration defaults, stored somewhere else: defaults = {'timeout': 200} conf = Configuration() # `timeout` is excluded from the serialization output: conf.model_dump() # {} # The `MISSING` value doesn't appear in the JSON Schema: Configuration.model_json_schema()['properties']['timeout'] #> {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'title': 'Timeout'}} # `is` can be used to discriminate between the sentinel and other values: timeout = conf.timeout if conf.timeout is not MISSING else defaults['timeout'] ``` This feature is marked as experimental because it relies on the draft [PEP 661](https://peps.python.org/pep-0661/), introducing sentinels in the standard library. As such, the following limitations currently apply: * Static type checking of sentinels is only supported with Pyright [1.1.402](https://github.com/microsoft/pyright/releases/tag/1.1.402) or greater, and the `enableExperimentalFeatures` type evaluation setting should be enabled. * Pickling of models containing `MISSING` as a value is not supported. !!! note When [applying constraints](./fields.md#field-constraints) to a union containing the `MISSING` sentinel, such constraints are automatically applied to the remaining type(s) of the union. pydantic-pydantic-ba0aa01/docs/concepts/fields.md000066400000000000000000000666051517143232300221610ustar00rootroot00000000000000??? api "API Documentation" [`pydantic.fields.Field`][pydantic.fields.Field]
In this section, we will go through the available mechanisms to customize Pydantic model fields: [default values](#default-values), [JSON Schema metadata](#customizing-json-schema), [constraints](#field-constraints), etc. To do so, the [`Field()`][pydantic.fields.Field] function is used a lot, and behaves the same way as the standard library [`field()`][dataclasses.field] function for dataclasses – by assigning to the annotated attribute: ```python from pydantic import BaseModel, Field class Model(BaseModel): name: str = Field(frozen=True) ``` !!! note Even though `name` is assigned a value, it is still required and has no default value. If you want to emphasize on the fact that a value must be provided, you can use the [ellipsis][Ellipsis]: ```python {lint="skip" test="skip"} class Model(BaseModel): name: str = Field(..., frozen=True) ``` However, its usage is discouraged as it doesn't play well with static type checkers. ## The annotated pattern To apply constraints or attach [`Field()`][pydantic.fields.Field] functions to a model field, Pydantic also supports the [`Annotated`][typing.Annotated] typing construct to attach metadata to an annotation: ```python from typing import Annotated from pydantic import BaseModel, Field, WithJsonSchema class Model(BaseModel): name: Annotated[str, Field(strict=True), WithJsonSchema({'extra': 'data'})] ``` As far as static type checkers are concerned, `name` is still typed as `str`, but Pydantic leverages the available metadata to add validation logic, type constraints, etc. Using this pattern has some advantages: * Using the `f: = Field(...)` form can be confusing and might trick users into thinking `f` has a default value, while in reality it is still required. * You can provide an arbitrary amount of metadata elements for a field. As shown in the example above, the [`Field()`][pydantic.fields.Field] function only supports a limited set of constraints/metadata, and you may have to use different Pydantic utilities such as [`WithJsonSchema`][pydantic.WithJsonSchema] in some cases. * Types can be made reusable (see the documentation on [custom types](./types.md#using-the-annotated-pattern) using this pattern). However, note that certain arguments to the [`Field()`][pydantic.fields.Field] function (namely, `default`, `default_factory`, and `alias`) are taken into account by static type checkers to synthesize a correct `__init__()` method. The annotated pattern is *not* understood by them, so you should use the normal assignment form instead. !!! tip The annotated pattern can also be used to add metadata to specific parts of the type. For instance, [validation constraints](#field-constraints) can be added this way: ```python from typing import Annotated from pydantic import BaseModel, Field class Model(BaseModel): int_list: list[Annotated[int, Field(gt=0)]] # Valid: [1, 3] # Invalid: [-1, 2] ``` Be careful not mixing *field* and *type* metadata: ```python {test="skip" lint="skip"} class Model(BaseModel): field_bad: Annotated[int, Field(deprecated=True)] | None = None # (1)! field_ok: Annotated[int | None, Field(deprecated=True)] = None # (2)! ``` 1. The [`Field()`][pydantic.fields.Field] function is applied to `int` type, hence the `deprecated` flag won't have any effect. While this may be confusing given that the name of the [`Field()`][pydantic.fields.Field] function would imply it should apply to the field, the API was designed when this function was the only way to provide metadata. You can alternatively make use of the [`annotated_types`](https://github.com/annotated-types/annotated-types) library which is now supported by Pydantic. 2. The [`Field()`][pydantic.fields.Field] function is applied to the "top-level" union type, hence the `deprecated` flag will be applied to the field. ## Inspecting model fields The fields of a model can be inspected using the [`model_fields`][pydantic.main.BaseModel.model_fields] class attribute (or the `__pydantic_fields__` attribute for [Pydantic dataclasses](./dataclasses.md)). It is a mapping of field names to their definition (represented as [`FieldInfo`][pydantic.fields.FieldInfo] instances). ```python from typing import Annotated from pydantic import BaseModel, Field, WithJsonSchema class Model(BaseModel): a: Annotated[ int, Field(gt=1), WithJsonSchema({'extra': 'data'}), Field(alias='b') ] = 1 field_info = Model.model_fields['a'] print(field_info.annotation) #> print(field_info.alias) #> b print(field_info.metadata) #> [Gt(gt=1), WithJsonSchema(json_schema={'extra': 'data'}, mode=None)] ``` /// deprecated-removed | v2.11 v3 [`model_fields`][pydantic.main.BaseModel.model_fields] can only be accessed from the class object, not the instance. /// ## Default values Default values for fields can be provided using the normal assignment syntax or by providing a value to the `default` argument: ```python from pydantic import BaseModel, Field class User(BaseModel): # Both fields aren't required: name: str = 'John Doe' age: int = Field(default=20) ``` /// version-changed | v2 [In Pydantic V1](../migration.md#required-optional-and-nullable-fields), a type annotated as [`Any`][typing.Any] or wrapped by [`Optional`][typing.Optional] would be given an implicit default of `None` even if no default was explicitly specified. This is no longer the case in Pydantic V2. /// You can also pass a callable to the `default_factory` argument that will be called to generate a default value: ```python from uuid import uuid4 from pydantic import BaseModel, Field class User(BaseModel): id: str = Field(default_factory=lambda: uuid4().hex) ``` [](){#default-factory-validated-data} The default factory can also take a single required argument, in which case the already validated data will be passed as a dictionary. ```python from pydantic import BaseModel, EmailStr, Field class User(BaseModel): email: EmailStr username: str = Field(default_factory=lambda data: data['email']) user = User(email='user@example.com') print(user.username) #> user@example.com ``` The `data` argument will *only* contain the already validated data, based on the [order of model fields](./models.md#field-ordering) (the above example would fail if `username` were to be defined before `email`). /// version-added | v2.10 Default factories can take already validated data as an argument. /// /// version-added | v2.13 Default factories for [private attributes](./models.md#private-model-attributes) can take the validated data as an argument. /// ## Validate default values By default, Pydantic will *not* validate default values. The `validate_default` field parameter (or the [`validate_default`][pydantic.ConfigDict.validate_default] configuration value) can be used to enable this behavior: ```python from pydantic import BaseModel, Field, ValidationError class User(BaseModel): age: int = Field(default='twelve', validate_default=True) try: user = User() except ValidationError as e: print(e) """ 1 validation error for User age Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='twelve', input_type=str] """ ``` ### Mutable default values A common source of bugs in Python is to use a mutable object as a default value for a function or method argument, as the same instance ends up being reused in each call. The [`dataclasses`][dataclasses] module actually raises an error in this case, indicating that you should use a [default factory](https://docs.python.org/3/library/dataclasses.html#default-factory-functions) instead. While the same thing can be done in Pydantic, it is not required. In the event that the default value is not hashable, Pydantic will create a deep copy of the default value when creating each instance of the model: ```python from pydantic import BaseModel class Model(BaseModel): item_counts: list[dict[str, int]] = [{}] m1 = Model() m1.item_counts[0]['a'] = 1 print(m1.item_counts) #> [{'a': 1}] m2 = Model() print(m2.item_counts) #> [{}] ``` ## Field aliases !!! tip Read more about aliases in the [dedicated section](./alias.md). For validation and serialization, you can define an alias for a field. There are three ways to define an alias: * `Field(alias='foo')` * `Field(validation_alias='foo')` * `Field(serialization_alias='foo')` The `alias` parameter is used for both validation *and* serialization. If you want to use *different* aliases for validation and serialization respectively, you can use the `validation_alias` and `serialization_alias` parameters, which will apply only in their respective use cases. Here is an example of using the `alias` parameter: ```python from pydantic import BaseModel, Field class User(BaseModel): name: str = Field(alias='username') user = User(username='johndoe') # (1)! print(user) #> name='johndoe' print(user.model_dump(by_alias=True)) # (2)! #> {'username': 'johndoe'} ``` 1. The alias `'username'` is used for instance creation and validation. 2. We are using [`model_dump()`][pydantic.main.BaseModel.model_dump] to convert the model into a serializable format. Note that the `by_alias` keyword argument defaults to `False`, and must be specified explicitly to dump models using the field (serialization) aliases. You can also use [`ConfigDict.serialize_by_alias`][pydantic.config.ConfigDict.serialize_by_alias] to configure this behavior at the model level. When `by_alias=True`, the alias `'username'` used during serialization. If you want to use an alias *only* for validation, you can use the `validation_alias` parameter: ```python from pydantic import BaseModel, Field class User(BaseModel): name: str = Field(validation_alias='username') user = User(username='johndoe') # (1)! print(user) #> name='johndoe' print(user.model_dump(by_alias=True)) # (2)! #> {'name': 'johndoe'} ``` 1. The validation alias `'username'` is used during validation. 2. The field name `'name'` is used during serialization. If you only want to define an alias for *serialization*, you can use the `serialization_alias` parameter: ```python from pydantic import BaseModel, Field class User(BaseModel): name: str = Field(serialization_alias='username') user = User(name='johndoe') # (1)! print(user) #> name='johndoe' print(user.model_dump(by_alias=True)) # (2)! #> {'username': 'johndoe'} ``` 1. The field name `'name'` is used for validation. 2. The serialization alias `'username'` is used for serialization. !!! note "Alias precedence and priority" In case you use `alias` together with `validation_alias` or `serialization_alias` at the same time, the `validation_alias` will have priority over `alias` for validation, and `serialization_alias` will have priority over `alias` for serialization. If you provide a value for the [`alias_generator`][pydantic.config.ConfigDict.alias_generator] model setting, you can control the order of precedence for field alias and generated aliases via the `alias_priority` field parameter. You can read more about alias precedence [here](../concepts/alias.md#alias-precedence). ??? tip "Static type checking/IDE support" If you provide a value for the `alias` field parameter, static type checkers will use this alias instead of the actual field name to synthesize the `__init__` method: ```python from pydantic import BaseModel, Field class User(BaseModel): name: str = Field(alias='username') user = User(username='johndoe') # (1)! ``` 1. Accepted by type checkers. This means that when using the [`validate_by_name`][pydantic.config.ConfigDict.validate_by_name] model setting (which allows both the field name and alias to be used during model validation), type checkers will error when the actual field name is used: ```python from pydantic import BaseModel, ConfigDict, Field class User(BaseModel): model_config = ConfigDict(validate_by_name=True) name: str = Field(alias='username') user = User(name='johndoe') # (1)! ``` 1. *Not* accepted by type checkers. If you still want type checkers to use the field name and not the alias, the [annotated pattern](#the-annotated-pattern) can be used (which is only understood by Pydantic): ```python from typing import Annotated from pydantic import BaseModel, ConfigDict, Field class User(BaseModel): model_config = ConfigDict(validate_by_name=True, validate_by_alias=True) name: Annotated[str, Field(alias='username')] user = User(name='johndoe') # (1)! user = User(username='johndoe') # (2)! ``` 1. Accepted by type checkers. 2. *Not* accepted by type checkers.

Validation Alias

Even though Pydantic treats `alias` and `validation_alias` the same when creating model instances, type checkers only understand the `alias` field parameter. As a workaround, you can instead specify both an `alias` and `serialization_alias` (identical to the field name), as the `serialization_alias` will override the `alias` during serialization: ```python from pydantic import BaseModel, Field class MyModel(BaseModel): my_field: int = Field(validation_alias='myValidationAlias') ``` with: ```python from pydantic import BaseModel, Field class MyModel(BaseModel): my_field: int = Field( alias='myValidationAlias', serialization_alias='my_field', ) m = MyModel(myValidationAlias=1) print(m.model_dump(by_alias=True)) #> {'my_field': 1} ``` [](){#numeric-constraints} [](){#string-constraints} [](){#decimal-constraints} ## Field constraints The [`Field()`][pydantic.Field] function can also be used to add constraints to specific types: ```python from decimal import Decimal from pydantic import BaseModel, Field class Model(BaseModel): positive: int = Field(gt=0) short_str: str = Field(max_length=3) precise_decimal: Decimal = Field(max_digits=5, decimal_places=2) ``` The available constraints for each type (and the way they affect the JSON Schema) are described in the [standard library types](../api/standard_library_types.md) documentation. !!! note When adding constraints to a union type, if a member of the union is `None` or the [`MISSING` sentinel](./experimental.md#missing-sentinel), the constraints will be automatically applied to the remaining type(s) of the union: ```python from typing import Annotated, Union from pydantic import BaseModel, Field class Model(BaseModel): positive: Union[int, None] = Field(gt=0) # Also works with the annotated pattern: negative: Annotated[Union[int, None], Field(lt=0)] ``` [](){#strict-mode} ## Strict fields The `strict` parameter of the [`Field()`][pydantic.Field] function specifies whether the field should be validated in [strict mode](./strict_mode.md). ```python from pydantic import BaseModel, Field class User(BaseModel): name: str = Field(strict=True) age: int = Field(strict=False) # (1)! user = User(name='John', age='42') # (2)! print(user) #> name='John' age=42 ``` 1. This is the default value. 2. The `age` field is validated in lax mode. Therefore, it can be assigned a string. The [standard library types](../api/standard_library_types.md) documentation describes the strict behavior for each type. [](){#dataclass-constraints} ## Dataclass fields Some parameters of the [`Field()`][pydantic.Field] function can be used on [dataclasses](./dataclasses.md): * `init`: Whether the field should be included in the synthesized `__init__()` method of the dataclass. * `init_var`: Whether the field should be [init-only][dataclasses-init-only-variables] in the dataclass. * `kw_only`: Whether the field should be a keyword-only argument in the constructor of the dataclass. Here is an example: ```python from pydantic import BaseModel, Field from pydantic.dataclasses import dataclass @dataclass class Foo: bar: str baz: str = Field(init_var=True) qux: str = Field(kw_only=True) class Model(BaseModel): foo: Foo model = Model(foo=Foo('bar', baz='baz', qux='qux')) print(model.model_dump()) # (1)! #> {'foo': {'bar': 'bar', 'qux': 'qux'}} ``` 1. The `baz` field is not included in the serialized output, since it is an init-only field. ## Field Representation The parameter `repr` can be used to control whether the field should be included in the string representation of the model. ```python from pydantic import BaseModel, Field class User(BaseModel): name: str = Field(repr=True) # (1)! age: int = Field(repr=False) user = User(name='John', age=42) print(user) #> name='John' ``` 1. This is the default value. ## Discriminator The parameter `discriminator` can be used to control the field that will be used to discriminate between different models in a union. It takes either the name of a field or a `Discriminator` instance. The `Discriminator` approach can be useful when the discriminator fields aren't the same for all the models in the `Union`. The following example shows how to use `discriminator` with a field name: ```python from typing import Literal, Union from pydantic import BaseModel, Field class Cat(BaseModel): pet_type: Literal['cat'] age: int class Dog(BaseModel): pet_type: Literal['dog'] age: int class Model(BaseModel): pet: Union[Cat, Dog] = Field(discriminator='pet_type') print(Model.model_validate({'pet': {'pet_type': 'cat', 'age': 12}})) # (1)! #> pet=Cat(pet_type='cat', age=12) ``` 1. See more about `model_validate()` in the [Validating data](./models.md#validating-data) documentation. The following example shows how to use the `discriminator` keyword argument with a `Discriminator` instance: ```python from typing import Annotated, Literal, Union from pydantic import BaseModel, Discriminator, Field, Tag class Cat(BaseModel): pet_type: Literal['cat'] age: int class Dog(BaseModel): pet_kind: Literal['dog'] age: int def pet_discriminator(v): if isinstance(v, dict): return v.get('pet_type', v.get('pet_kind')) return getattr(v, 'pet_type', getattr(v, 'pet_kind', None)) class Model(BaseModel): pet: Union[Annotated[Cat, Tag('cat')], Annotated[Dog, Tag('dog')]] = Field( discriminator=Discriminator(pet_discriminator) ) print(repr(Model.model_validate({'pet': {'pet_type': 'cat', 'age': 12}}))) #> Model(pet=Cat(pet_type='cat', age=12)) print(repr(Model.model_validate({'pet': {'pet_kind': 'dog', 'age': 12}}))) #> Model(pet=Dog(pet_kind='dog', age=12)) ``` You can also take advantage of `Annotated` to define your discriminated unions. See the [Discriminated Unions](./unions.md#discriminated-unions) documentation for more details. ## Immutability The parameter `frozen` is used to emulate the frozen dataclass behaviour. It is used to prevent the field from being assigned a new value after the model is created (immutability). See the [frozen dataclass documentation] for more details. ```python from pydantic import BaseModel, Field, ValidationError class User(BaseModel): name: str = Field(frozen=True) age: int user = User(name='John', age=42) try: user.name = 'Jane' # (1)! except ValidationError as e: print(e) """ 1 validation error for User name Field is frozen [type=frozen_field, input_value='Jane', input_type=str] """ ``` 1. Since `name` field is frozen, the assignment is not allowed. [](){#exclude} ## Excluding fields The `exclude` and `exclude_if` parameters can be used to control which fields should be excluded from the model when exporting the model. See the following example: ```python from pydantic import BaseModel, Field class User(BaseModel): name: str age: int = Field(exclude=True) user = User(name='John', age=42) print(user.model_dump()) # (1)! #> {'name': 'John'} ``` 1. The `age` field is not included in the [`model_dump()`][pydantic.BaseModel.model_dump] output, since it is excluded. See the dedicated [serialization section](./serialization.md#field-inclusion-and-exclusion) for more details. /// version-added | v2.12 The `exclude_if` parameter. /// ## Deprecated fields /// version-added | v2.7.0 /// The `deprecated` parameter can be used to mark a field as being deprecated. Doing so will result in: * a runtime deprecation warning emitted when accessing the field. * The [deprecated](https://json-schema.org/draft/2020-12/json-schema-validation#section-9.3) keyword being set in the generated JSON schema. This parameter accepts different types, described below. ### `deprecated` as a string The value will be used as the deprecation message. ```python from typing import Annotated from pydantic import BaseModel, Field class Model(BaseModel): deprecated_field: Annotated[int, Field(deprecated='This is deprecated')] print(Model.model_json_schema()['properties']['deprecated_field']) #> {'deprecated': True, 'title': 'Deprecated Field', 'type': 'integer'} ``` ### `deprecated` via the `@warnings.deprecated` decorator The [`@warnings.deprecated`][warnings.deprecated] decorator (or the [`typing_extensions` backport][typing_extensions.deprecated] on Python 3.12 and lower) can be used as an instance. === "Python 3.9 and above" ```python from typing import Annotated from typing_extensions import deprecated from pydantic import BaseModel, Field class Model(BaseModel): deprecated_field: Annotated[int, deprecated('This is deprecated')] # Or explicitly using `Field`: alt_form: Annotated[int, Field(deprecated=deprecated('This is deprecated'))] ``` === "Python 3.13 and above" ```python {requires="3.13"} from typing import Annotated from warnings import deprecated from pydantic import BaseModel, Field class Model(BaseModel): deprecated_field: Annotated[int, deprecated('This is deprecated')] # Or explicitly using `Field`: alt_form: Annotated[int, Field(deprecated=deprecated('This is deprecated'))] ``` !!! note "Support for `category` and `stacklevel`" The current implementation of this feature does not take into account the `category` and `stacklevel` arguments to the `deprecated` decorator. This might land in a future version of Pydantic. ### `deprecated` as a boolean ```python from typing import Annotated from pydantic import BaseModel, Field class Model(BaseModel): deprecated_field: Annotated[int, Field(deprecated=True)] print(Model.model_json_schema()['properties']['deprecated_field']) #> {'deprecated': True, 'title': 'Deprecated Field', 'type': 'integer'} ``` !!! warning "Accessing a deprecated field in validators" When accessing a deprecated field inside a validator, the deprecation warning will be emitted. You can use [`catch_warnings`][warnings.catch_warnings] to explicitly ignore it: ```python import warnings from typing_extensions import Self from pydantic import BaseModel, Field, model_validator class Model(BaseModel): deprecated_field: int = Field(deprecated='This is deprecated') @model_validator(mode='after') def validate_model(self) -> Self: with warnings.catch_warnings(): warnings.simplefilter('ignore', DeprecationWarning) self.deprecated_field = self.deprecated_field * 2 ``` ## Customizing JSON Schema Some field parameters are used exclusively to customize the generated JSON schema. The parameters in question are: * `title` * `description` * `examples` * `json_schema_extra` Read more about JSON schema customization / modification with fields in the [Customizing JSON Schema] section of the JSON schema docs. ## The `computed_field` decorator ??? api "API Documentation" [`@computed_field`][pydantic.fields.computed_field]
/// version-added | v2.13 Computed fields can be conditionally excluded from the serialization output by using the `exclude_if` parameter of the decorator. /// The [`@computed_field`][pydantic.fields.computed_field] decorator can be used to include [properties][property] (or [cached properties][functools.cached_property]) when serializing a model or dataclass. The property will also be included in the JSON Schema (in serialization mode). !!! note Properties can be useful for fields that are computed from other fields, or for fields that are expensive to be computed (and thus, are cached if using [`@cached_property`][functools.cached_property]). However, note that Pydantic will *not* perform any additional logic on the wrapped property (validation, cache invalidation, etc.). Here's an example of the JSON schema (in serialization mode) generated for a model with a computed field: ```python from pydantic import BaseModel, computed_field class Box(BaseModel): width: float height: float depth: float @computed_field @property # (1)! def volume(self) -> float: return self.width * self.height * self.depth print(Box.model_json_schema(mode='serialization')) """ { 'properties': { 'width': {'title': 'Width', 'type': 'number'}, 'height': {'title': 'Height', 'type': 'number'}, 'depth': {'title': 'Depth', 'type': 'number'}, 'volume': {'readOnly': True, 'title': 'Volume', 'type': 'number'}, }, 'required': ['width', 'height', 'depth', 'volume'], 'title': 'Box', 'type': 'object', } """ ``` 1. If not specified, [`@computed_field`][pydantic.fields.computed_field] will implicitly convert the method to a [`@property`][property]. However, it is preferable to explicitly use the [`@property`][property] decorator for type checking purposes. Here's an example using the [`model_dump()`][pydantic.BaseModel.model_dump] method with a computed field: ```python from pydantic import BaseModel, computed_field class Box(BaseModel): width: float height: float depth: float @computed_field @property def volume(self) -> float: return self.width * self.height * self.depth b = Box(width=1, height=2, depth=3) print(b.model_dump()) #> {'width': 1.0, 'height': 2.0, 'depth': 3.0, 'volume': 6.0} ``` As with regular fields, computed fields can be marked as being deprecated: ```python from typing_extensions import deprecated from pydantic import BaseModel, computed_field class Box(BaseModel): width: float height: float depth: float @computed_field @property @deprecated("'volume' is deprecated") def volume(self) -> float: return self.width * self.height * self.depth ``` [frozen dataclass documentation]: https://docs.python.org/3/library/dataclasses.html#frozen-instances [Customizing JSON Schema]: json_schema.md#field-level-customization pydantic-pydantic-ba0aa01/docs/concepts/forward_annotations.md000066400000000000000000000147771517143232300247770ustar00rootroot00000000000000Forward annotations (wrapped in quotes) or using the `from __future__ import annotations` [future statement] (as introduced in [PEP563](https://www.python.org/dev/peps/pep-0563/)) are supported: ```python from __future__ import annotations from pydantic import BaseModel MyInt = int class Model(BaseModel): a: MyInt # Without the future import, equivalent to: # a: 'MyInt' print(Model(a='1')) #> a=1 ``` As shown in the following sections, forward annotations are useful when you want to reference a type that is not yet defined in your code. The internal logic to resolve forward annotations is described in detail in [this section](../internals/resolving_annotations.md). ## Self-referencing (or "Recursive") Models Models with self-referencing fields are also supported. These annotations will be resolved during model creation. Within the model, you can either add the `from __future__ import annotations` import or wrap the annotation in a string: ```python from typing import Optional from pydantic import BaseModel class Foo(BaseModel): a: int = 123 sibling: 'Optional[Foo]' = None print(Foo()) #> a=123 sibling=None print(Foo(sibling={'a': '321'})) #> a=123 sibling=Foo(a=321, sibling=None) ``` ### Cyclic references When working with self-referencing recursive models, it is possible that you might encounter cyclic references in validation inputs. For example, this can happen when validating ORM instances with back-references from attributes. Rather than raising a [`RecursionError`][] while attempting to validate data with cyclic references, Pydantic is able to detect the cyclic reference and raise an appropriate [`ValidationError`][pydantic_core.ValidationError]: ```python from typing import Optional from pydantic import BaseModel, ValidationError class ModelA(BaseModel): b: 'Optional[ModelB]' = None class ModelB(BaseModel): a: Optional[ModelA] = None cyclic_data = {} cyclic_data['a'] = {'b': cyclic_data} print(cyclic_data) #> {'a': {'b': {...}}} try: ModelB.model_validate(cyclic_data) except ValidationError as exc: print(exc) """ 1 validation error for ModelB a.b Recursion error - cyclic reference detected [type=recursion_loop, input_value={'a': {'b': {...}}}, input_type=dict] """ ``` Because this error is raised without actually exceeding the maximum recursion depth, you can catch and handle the raised [`ValidationError`][pydantic_core.ValidationError] without needing to worry about the limited remaining recursion depth: ```python from __future__ import annotations from collections.abc import Generator from contextlib import contextmanager from dataclasses import field from pydantic import BaseModel, ValidationError, field_validator def is_recursion_validation_error(exc: ValidationError) -> bool: errors = exc.errors() return len(errors) == 1 and errors[0]['type'] == 'recursion_loop' @contextmanager def suppress_recursion_validation_error() -> Generator[None]: try: yield except ValidationError as exc: if not is_recursion_validation_error(exc): raise exc class Node(BaseModel): id: int children: list[Node] = field(default_factory=list) @field_validator('children', mode='wrap') @classmethod def drop_cyclic_references(cls, children, h): try: return h(children) except ValidationError as exc: if not ( is_recursion_validation_error(exc) and isinstance(children, list) ): raise exc value_without_cyclic_refs = [] for child in children: with suppress_recursion_validation_error(): value_without_cyclic_refs.extend(h([child])) return h(value_without_cyclic_refs) # Create data with cyclic references representing the graph 1 -> 2 -> 3 -> 1 node_data = {'id': 1, 'children': [{'id': 2, 'children': [{'id': 3}]}]} node_data['children'][0]['children'][0]['children'] = [node_data] print(Node.model_validate(node_data)) #> id=1 children=[Node(id=2, children=[Node(id=3, children=[])])] ``` Similarly, if Pydantic encounters a recursive reference during *serialization*, rather than waiting for the maximum recursion depth to be exceeded, a [`ValueError`][] is raised immediately: ```python from pydantic import TypeAdapter # Create data with cyclic references representing the graph 1 -> 2 -> 3 -> 1 node_data = {'id': 1, 'children': [{'id': 2, 'children': [{'id': 3}]}]} node_data['children'][0]['children'][0]['children'] = [node_data] try: # Try serializing the circular reference as JSON TypeAdapter(dict).dump_json(node_data) except ValueError as exc: print(exc) """ Error serializing to JSON: ValueError: Circular reference detected (id repeated) """ ``` This can also be handled if desired: ```python from dataclasses import field from typing import Any from pydantic import ( SerializerFunctionWrapHandler, TypeAdapter, field_serializer, ) from pydantic.dataclasses import dataclass @dataclass class NodeReference: id: int @dataclass class Node(NodeReference): children: list['Node'] = field(default_factory=list) @field_serializer('children', mode='wrap') def serialize( self, children: list['Node'], handler: SerializerFunctionWrapHandler ) -> Any: """ Serialize a list of nodes, handling circular references by excluding the children. """ try: return handler(children) except ValueError as exc: if not str(exc).startswith('Circular reference'): raise exc result = [] for node in children: try: serialized = handler([node]) except ValueError as exc: if not str(exc).startswith('Circular reference'): raise exc result.append({'id': node.id}) else: result.append(serialized) return result # Create a cyclic graph: nodes = [Node(id=1), Node(id=2), Node(id=3)] nodes[0].children.append(nodes[1]) nodes[1].children.append(nodes[2]) nodes[2].children.append(nodes[0]) print(nodes[0]) #> Node(id=1, children=[Node(id=2, children=[Node(id=3, children=[...])])]) # Serialize the cyclic graph: print(TypeAdapter(Node).dump_python(nodes[0])) """ { 'id': 1, 'children': [{'id': 2, 'children': [{'id': 3, 'children': [{'id': 1}]}]}], } """ ``` [future statement]: https://docs.python.org/3/reference/simple_stmts.html#future pydantic-pydantic-ba0aa01/docs/concepts/json.md000066400000000000000000000210501517143232300216450ustar00rootroot00000000000000# JSON ## Json Parsing ??? api "API Documentation" [`pydantic.main.BaseModel.model_validate_json`][pydantic.main.BaseModel.model_validate_json] [`pydantic.type_adapter.TypeAdapter.validate_json`][pydantic.type_adapter.TypeAdapter.validate_json] [`pydantic_core.from_json`][pydantic_core.from_json] Pydantic provides builtin JSON parsing, which helps achieve: * Significant performance improvements without the cost of using a 3rd party library * Support for custom errors * Support for `strict` specifications Here's an example of Pydantic's builtin JSON parsing via the [`model_validate_json`][pydantic.main.BaseModel.model_validate_json] method, showcasing the support for `strict` specifications while parsing JSON data that doesn't match the model's type annotations: ```python from datetime import date from pydantic import BaseModel, ConfigDict, ValidationError class Event(BaseModel): model_config = ConfigDict(strict=True) when: date where: tuple[int, int] json_data = '{"when": "1987-01-28", "where": [51, -1]}' print(Event.model_validate_json(json_data)) # (1)! #> when=datetime.date(1987, 1, 28) where=(51, -1) try: Event.model_validate({'when': '1987-01-28', 'where': [51, -1]}) # (2)! except ValidationError as e: print(e) """ 2 validation errors for Event when Input should be a valid date [type=date_type, input_value='1987-01-28', input_type=str] where Input should be a valid tuple [type=tuple_type, input_value=[51, -1], input_type=list] """ ``` 1. JSON has no `date` or tuple types, but Pydantic knows that so allows strings and arrays as inputs respectively when parsing JSON directly. 2. If you pass the same values to the [`model_validate`][pydantic.main.BaseModel.model_validate] method, Pydantic will raise a validation error because the `strict` configuration is enabled. In v2.5.0 and above, Pydantic uses [`jiter`](https://docs.rs/jiter/latest/jiter/), a fast and iterable JSON parser, to parse JSON data. Using `jiter` compared to `serde` results in modest performance improvements that will get even better in the future. The `jiter` JSON parser is almost entirely compatible with the `serde` JSON parser, with one noticeable enhancement being that `jiter` supports deserialization of `inf` and `NaN` values. In the future, `jiter` is intended to enable support validation errors to include the location in the original JSON input which contained the invalid value. ### Partial JSON Parsing **Starting in v2.7.0**, Pydantic's [JSON parser](https://docs.rs/jiter/latest/jiter/) offers support for partial JSON parsing, which is exposed via [`pydantic_core.from_json`][pydantic_core.from_json]. Here's an example of this feature in action: ```python from pydantic_core import from_json partial_json_data = '["aa", "bb", "c' # (1)! try: result = from_json(partial_json_data, allow_partial=False) except ValueError as e: print(e) # (2)! #> EOF while parsing a string at line 1 column 15 result = from_json(partial_json_data, allow_partial=True) print(result) # (3)! #> ['aa', 'bb'] ``` 1. The JSON list is incomplete - it's missing a closing `"]` 2. When `allow_partial` is set to `False` (the default), a parsing error occurs. 3. When `allow_partial` is set to `True`, part of the input is deserialized successfully. This also works for deserializing partial dictionaries. For example: ```python from pydantic_core import from_json partial_dog_json = '{"breed": "lab", "name": "fluffy", "friends": ["buddy", "spot", "rufus"], "age' dog_dict = from_json(partial_dog_json, allow_partial=True) print(dog_dict) #> {'breed': 'lab', 'name': 'fluffy', 'friends': ['buddy', 'spot', 'rufus']} ``` !!! tip "Validating LLM Output" This feature is particularly beneficial for validating LLM outputs. We've written some blog posts about this topic, which you can find on [our website](https://pydantic.dev/articles). In future versions of Pydantic, we expect to expand support for this feature through either Pydantic's other JSON validation functions ([`pydantic.main.BaseModel.model_validate_json`][pydantic.main.BaseModel.model_validate_json] and [`pydantic.type_adapter.TypeAdapter.validate_json`][pydantic.type_adapter.TypeAdapter.validate_json]) or model configuration. Stay tuned 🚀! For now, you can use [`pydantic_core.from_json`][pydantic_core.from_json] in combination with [`pydantic.main.BaseModel.model_validate`][pydantic.main.BaseModel.model_validate] to achieve the same result. Here's an example: ```python from pydantic_core import from_json from pydantic import BaseModel class Dog(BaseModel): breed: str name: str friends: list partial_dog_json = '{"breed": "lab", "name": "fluffy", "friends": ["buddy", "spot", "rufus"], "age' dog = Dog.model_validate(from_json(partial_dog_json, allow_partial=True)) print(repr(dog)) #> Dog(breed='lab', name='fluffy', friends=['buddy', 'spot', 'rufus']) ``` !!! tip For partial JSON parsing to work reliably, all fields on the model should have default values. Check out the following example for a more in-depth look at how to use default values with partial JSON parsing: !!! example "Using default values with partial JSON parsing" ```python from typing import Annotated, Any, Optional import pydantic_core from pydantic import BaseModel, ValidationError, WrapValidator def default_on_error(v, handler) -> Any: """ Raise a PydanticUseDefault exception if the value is missing. This is useful for avoiding errors from partial JSON preventing successful validation. """ try: return handler(v) except ValidationError as exc: # there might be other types of errors resulting from partial JSON parsing # that you allow here, feel free to customize as needed if all(e['type'] == 'missing' for e in exc.errors()): raise pydantic_core.PydanticUseDefault() else: raise class NestedModel(BaseModel): x: int y: str class MyModel(BaseModel): foo: Optional[str] = None bar: Annotated[ Optional[tuple[str, int]], WrapValidator(default_on_error) ] = None nested: Annotated[ Optional[NestedModel], WrapValidator(default_on_error) ] = None m = MyModel.model_validate( pydantic_core.from_json('{"foo": "x", "bar": ["world",', allow_partial=True) ) print(repr(m)) #> MyModel(foo='x', bar=None, nested=None) m = MyModel.model_validate( pydantic_core.from_json( '{"foo": "x", "bar": ["world", 1], "nested": {"x":', allow_partial=True ) ) print(repr(m)) #> MyModel(foo='x', bar=('world', 1), nested=None) ``` ### Caching Strings **Starting in v2.7.0**, Pydantic's [JSON parser](https://docs.rs/jiter/latest/jiter/) offers support for configuring how Python strings are cached during JSON parsing and validation (when Python strings are constructed from Rust strings during Python validation, e.g. after `strip_whitespace=True`). The `cache_strings` setting is exposed via both [model config][pydantic.config.ConfigDict] and [`pydantic_core.from_json`][pydantic_core.from_json]. The `cache_strings` setting can take any of the following values: * `True` or `'all'` (the default): cache all strings * `'keys'`: cache only dictionary keys, this **only** applies when used with [`pydantic_core.from_json`][pydantic_core.from_json] or when parsing JSON using [`Json`][pydantic.types.Json] * `False` or `'none'`: no caching Using the string caching feature results in performance improvements, but increases memory usage slightly. !!! note "String Caching Details" 1. Strings are cached using a fully associative cache with a size of [16,384](https://github.com/pydantic/jiter/blob/5bbdcfd22882b7b286416b22f74abd549c7b2fd7/src/py_string_cache.rs#L113). 2. Only strings where `len(string) < 64` are cached. 3. There is some overhead to looking up the cache, which is normally worth it to avoid constructing strings. However, if you know there will be very few repeated strings in your data, you might get a performance boost by disabling this setting with `cache_strings=False`. ## JSON Serialization ??? api "API Documentation" [`pydantic.main.BaseModel.model_dump_json`][pydantic.main.BaseModel.model_dump_json]
[`pydantic.type_adapter.TypeAdapter.dump_json`][pydantic.type_adapter.TypeAdapter.dump_json]
[`pydantic_core.to_json`][pydantic_core.to_json]
For more information on JSON serialization, see the [serialization concepts](./serialization.md) page. pydantic-pydantic-ba0aa01/docs/concepts/json_schema.md000066400000000000000000001071151517143232300231740ustar00rootroot00000000000000??? api "API Documentation" [`pydantic.json_schema`][pydantic.json_schema]
Pydantic allows automatic creation and customization of JSON schemas from models. The generated JSON schemas are compliant with the following specifications: * [JSON Schema Draft 2020-12](https://json-schema.org/draft/2020-12/release-notes.html) * [OpenAPI Specification v3.1.0](https://github.com/OAI/OpenAPI-Specification). ## Generating JSON Schema Use the following functions to generate JSON schema: * [`BaseModel.model_json_schema`][pydantic.main.BaseModel.model_json_schema] returns a jsonable dict of a model's schema. * [`TypeAdapter.json_schema`][pydantic.type_adapter.TypeAdapter.json_schema] returns a jsonable dict of an adapted type's schema. !!! note These methods are not to be confused with [`BaseModel.model_dump_json`][pydantic.main.BaseModel.model_dump_json] and [`TypeAdapter.dump_json`][pydantic.type_adapter.TypeAdapter.dump_json], which serialize instances of the model or adapted type, respectively. These methods return JSON strings. In comparison, [`BaseModel.model_json_schema`][pydantic.main.BaseModel.model_json_schema] and [`TypeAdapter.json_schema`][pydantic.type_adapter.TypeAdapter.json_schema] return a jsonable dict representing the JSON schema of the model or adapted type, respectively. !!! note "on the "jsonable" nature of JSON schema" Regarding the "jsonable" nature of the [`model_json_schema`][pydantic.main.BaseModel.model_json_schema] results, calling `json.dumps(m.model_json_schema())`on some `BaseModel` `m` returns a valid JSON string. Similarly, for [`TypeAdapter.json_schema`][pydantic.type_adapter.TypeAdapter.json_schema], calling `json.dumps(TypeAdapter().json_schema())` returns a valid JSON string. !!! tip Pydantic offers support for both of: 1. [Customizing JSON Schema](#customizing-json-schema) 2. [Customizing the JSON Schema Generation Process](#customizing-the-json-schema-generation-process) The first approach generally has a more narrow scope, allowing for customization of the JSON schema for more specific cases and types. The second approach generally has a more broad scope, allowing for customization of the JSON schema generation process overall. The same effects can be achieved with either approach, but depending on your use case, one approach might offer a more simple solution than the other. Here's an example of generating JSON schema from a `BaseModel`: ```python {output="json"} import json from enum import Enum from typing import Annotated, Union from pydantic import BaseModel, Field from pydantic.config import ConfigDict class FooBar(BaseModel): count: int size: Union[float, None] = None class Gender(str, Enum): male = 'male' female = 'female' other = 'other' not_given = 'not_given' class MainModel(BaseModel): """ This is the description of the main model """ model_config = ConfigDict(title='Main') foo_bar: FooBar gender: Annotated[Union[Gender, None], Field(alias='Gender')] = None snap: int = Field( default=42, title='The Snap', description='this is the value of snap', gt=30, lt=50, ) main_model_schema = MainModel.model_json_schema() # (1)! print(json.dumps(main_model_schema, indent=2)) # (2)! """ { "$defs": { "FooBar": { "properties": { "count": { "title": "Count", "type": "integer" }, "size": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "default": null, "title": "Size" } }, "required": [ "count" ], "title": "FooBar", "type": "object" }, "Gender": { "enum": [ "male", "female", "other", "not_given" ], "title": "Gender", "type": "string" } }, "description": "This is the description of the main model", "properties": { "foo_bar": { "$ref": "#/$defs/FooBar" }, "Gender": { "anyOf": [ { "$ref": "#/$defs/Gender" }, { "type": "null" } ], "default": null }, "snap": { "default": 42, "description": "this is the value of snap", "exclusiveMaximum": 50, "exclusiveMinimum": 30, "title": "The Snap", "type": "integer" } }, "required": [ "foo_bar" ], "title": "Main", "type": "object" } """ ``` 1. This produces a "jsonable" dict of `MainModel`'s schema. 2. Calling `json.dumps` on the schema dict produces a JSON string. The [`TypeAdapter`][pydantic.type_adapter.TypeAdapter] class lets you create an object with methods for validating, serializing, and producing JSON schemas for arbitrary types. This serves as a complete replacement for `schema_of` in Pydantic V1 (which is now deprecated). Here's an example of generating JSON schema from a [`TypeAdapter`][pydantic.type_adapter.TypeAdapter]: ```python from pydantic import TypeAdapter adapter = TypeAdapter(list[int]) print(adapter.json_schema()) #> {'items': {'type': 'integer'}, 'type': 'array'} ``` You can also generate JSON schemas for combinations of [`BaseModel`s][pydantic.main.BaseModel] and [`TypeAdapter`s][pydantic.type_adapter.TypeAdapter], as shown in this example: ```python {output="json"} import json from typing import Union from pydantic import BaseModel, TypeAdapter class Cat(BaseModel): name: str color: str class Dog(BaseModel): name: str breed: str ta = TypeAdapter(Union[Cat, Dog]) ta_schema = ta.json_schema() print(json.dumps(ta_schema, indent=2)) """ { "$defs": { "Cat": { "properties": { "name": { "title": "Name", "type": "string" }, "color": { "title": "Color", "type": "string" } }, "required": [ "name", "color" ], "title": "Cat", "type": "object" }, "Dog": { "properties": { "name": { "title": "Name", "type": "string" }, "breed": { "title": "Breed", "type": "string" } }, "required": [ "name", "breed" ], "title": "Dog", "type": "object" } }, "anyOf": [ { "$ref": "#/$defs/Cat" }, { "$ref": "#/$defs/Dog" } ] } """ ``` ### Configuring the `JsonSchemaMode` Specify the mode of JSON schema generation via the `mode` parameter in the [`model_json_schema`][pydantic.main.BaseModel.model_json_schema] and [`TypeAdapter.json_schema`][pydantic.type_adapter.TypeAdapter.json_schema] methods. By default, the mode is set to `'validation'`, which produces a JSON schema corresponding to the model's validation schema. The [`JsonSchemaMode`][pydantic.json_schema.JsonSchemaMode] is a type alias that represents the available options for the `mode` parameter: * `'validation'` * `'serialization'` Here's an example of how to specify the `mode` parameter, and how it affects the generated JSON schema: ```python from decimal import Decimal from pydantic import BaseModel class Model(BaseModel): a: Decimal = Decimal('12.34') print(Model.model_json_schema(mode='validation')) """ { 'properties': { 'a': { 'anyOf': [ {'type': 'number'}, { 'pattern': '^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$', 'type': 'string', }, ], 'default': '12.34', 'title': 'A', } }, 'title': 'Model', 'type': 'object', } """ print(Model.model_json_schema(mode='serialization')) """ { 'properties': { 'a': { 'default': '12.34', 'pattern': '^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$', 'title': 'A', 'type': 'string', } }, 'title': 'Model', 'type': 'object', } """ ``` ## Customizing JSON Schema The generated JSON schema can be customized at both the [field level](#field-level-customization) and [model level](#model-level-customization). At both the field and model levels, you can use the [`json_schema_extra` option](#using-json_schema_extra) to add extra information to the JSON schema. For custom types, Pydantic offers other tools for customizing JSON schema generation: 1. [`WithJsonSchema` annotation](#withjsonschema-annotation) 2. [`SkipJsonSchema` annotation](#skipjsonschema-annotation) 3. [Implementing `__get_pydantic_core_schema__`](#implementing_get_pydantic_core_schema) 4. [Implementing `__get_pydantic_json_schema__`](#implementing_get_pydantic_json_schema) ### Field-Level Customization [Fields](./fields.md) can have their JSON Schema customized. This is usually done using the [`Field()`][pydantic.fields.Field] function. Some field parameters are used exclusively to customize the generated JSON Schema: * `title`: The title of the field. * `description`: The description of the field. * `examples`: The examples of the field. * `json_schema_extra`: Extra JSON Schema properties to be added to the field (see the [dedicated documentation](#using-json_schema_extra)). * `field_title_generator`: A function that programmatically sets the field's title, based on its name and info. Here's an example: ```python {output="json"} import json from typing import Annotated from pydantic import BaseModel, EmailStr, Field, SecretStr class User(BaseModel): age: int = Field(description='Age of the user') email: Annotated[EmailStr, Field(examples=['marcelo@mail.com'])] # (1)! name: str = Field(title='Username') password: SecretStr = Field( json_schema_extra={ 'title': 'Password', 'description': 'Password of the user', 'examples': ['123456'], } ) print(json.dumps(User.model_json_schema(), indent=2)) """ { "properties": { "age": { "description": "Age of the user", "title": "Age", "type": "integer" }, "email": { "examples": [ "marcelo@mail.com" ], "format": "email", "title": "Email", "type": "string" }, "name": { "title": "Username", "type": "string" }, "password": { "description": "Password of the user", "examples": [ "123456" ], "format": "password", "title": "Password", "type": "string", "writeOnly": true } }, "required": [ "age", "email", "name", "password" ], "title": "User", "type": "object" } """ ``` 1. The [annotated pattern](./fields.md#the-annotated-pattern) can also be used. ### Programmatic field title generation The `field_title_generator` parameter can be used to programmatically generate the title for a field based on its name and info. See the following example: ```python import json from pydantic import BaseModel, Field from pydantic.fields import FieldInfo def make_title(field_name: str, field_info: FieldInfo) -> str: return field_name.upper() class Person(BaseModel): name: str = Field(field_title_generator=make_title) age: int = Field(field_title_generator=make_title) print(json.dumps(Person.model_json_schema(), indent=2)) """ { "properties": { "name": { "title": "NAME", "type": "string" }, "age": { "title": "AGE", "type": "integer" } }, "required": [ "name", "age" ], "title": "Person", "type": "object" } """ ``` ### Model-Level Customization You can also use [model config][pydantic.config.ConfigDict] to customize JSON schema generation on a model. Specifically, the following config options are relevant: * [`title`][pydantic.config.ConfigDict.title] * [`json_schema_extra`][pydantic.config.ConfigDict.json_schema_extra] * [`json_schema_mode_override`][pydantic.config.ConfigDict.json_schema_mode_override] * [`field_title_generator`][pydantic.config.ConfigDict.field_title_generator] * [`model_title_generator`][pydantic.config.ConfigDict.model_title_generator] ### Using `json_schema_extra` The `json_schema_extra` option can be used to add extra information to the JSON schema, either at the [Field level](#field-level-customization) or at the [Model level](#model-level-customization). You can pass a `dict` or a `Callable` to `json_schema_extra`. #### Using `json_schema_extra` with a `dict` You can pass a `dict` to `json_schema_extra` to add extra information to the JSON schema: ```python {output="json"} import json from pydantic import BaseModel, ConfigDict class Model(BaseModel): a: str model_config = ConfigDict(json_schema_extra={'examples': [{'a': 'Foo'}]}) print(json.dumps(Model.model_json_schema(), indent=2)) """ { "examples": [ { "a": "Foo" } ], "properties": { "a": { "title": "A", "type": "string" } }, "required": [ "a" ], "title": "Model", "type": "object" } """ ``` #### Using `json_schema_extra` with a `Callable` You can pass a `Callable` to `json_schema_extra` to modify the JSON schema with a function: ```python {output="json"} import json from pydantic import BaseModel, Field def pop_default(s): s.pop('default') class Model(BaseModel): a: int = Field(default=1, json_schema_extra=pop_default) print(json.dumps(Model.model_json_schema(), indent=2)) """ { "properties": { "a": { "title": "A", "type": "integer" } }, "title": "Model", "type": "object" } """ ``` #### Merging `json_schema_extra` Starting in v2.9, Pydantic merges `json_schema_extra` dictionaries from annotated types. This pattern offers a more additive approach to merging rather than the previous override behavior. This can be quite helpful for cases of reusing json schema extra information across multiple types. We viewed this change largely as a bug fix, as it resolves unintentional differences in the `json_schema_extra` merging behavior between `BaseModel` and `TypeAdapter` instances - see [this issue](https://github.com/pydantic/pydantic/issues/9210) for more details. ```python import json from typing import Annotated from typing_extensions import TypeAlias from pydantic import Field, TypeAdapter ExternalType: TypeAlias = Annotated[ int, Field(json_schema_extra={'key1': 'value1'}) ] ta = TypeAdapter( Annotated[ExternalType, Field(json_schema_extra={'key2': 'value2'})] ) print(json.dumps(ta.json_schema(), indent=2)) """ { "key1": "value1", "key2": "value2", "type": "integer" } """ ``` !!! note We no longer (and never fully did) support composing a mix of `dict` and `callable` type `json_schema_extra` specifications. If this is a requirement for your use case, please [open a pydantic issue](https://github.com/pydantic/pydantic/issues/new/choose) and explain your situation - we'd be happy to reconsider this decision when presented with a compelling case. ### `WithJsonSchema` annotation !!! tip Using [`WithJsonSchema`][pydantic.json_schema.WithJsonSchema] is preferred over [implementing `__get_pydantic_json_schema__()`](#implementing_get_pydantic_json_schema) for custom types, as it's more simple and less error-prone. An annotation used to override the JSON Schema for a type. This is useful when you want to set a JSON Schema for a type that don't produce any JSON Schemas by default (e.g. [`Callable`][collections.abc.Callable]). Note that this overrides the whole generated JSON Schema for the type (in the following example, the `'type'` also needs to be provided). ```python {output="json"} import json from typing import Annotated from pydantic import BaseModel, WithJsonSchema MyInt = Annotated[ int, WithJsonSchema({'type': 'integer', 'examples': [1, 0, -1]}), ] class Model(BaseModel): a: MyInt print(json.dumps(Model.model_json_schema(), indent=2)) """ { "properties": { "a": { "examples": [ 1, 0, -1 ], "title": "A", "type": "integer" } }, "required": [ "a" ], "title": "Model", "type": "object" } """ ``` See the [API documentation][pydantic.json_schema.WithJsonSchema] for more details. !!! note You might be tempted to use the [`WithJsonSchema`][pydantic.json_schema.WithJsonSchema] annotation to fine-tune the JSON Schema of fields having [validators](./validators.md) attached. Instead, it is recommended to use [the `json_schema_input_type` argument](./validators.md#json-schema-and-field-validators). ### `SkipJsonSchema` annotation ??? api "API Documentation" [`pydantic.json_schema.SkipJsonSchema`][pydantic.json_schema.SkipJsonSchema]
The [`SkipJsonSchema`][pydantic.json_schema.SkipJsonSchema] annotation can be used to skip an included field (or part of a field's specifications) from the generated JSON schema. See the API docs for more details. ### Implementing `__get_pydantic_core_schema__` Custom types (used as `field_name: TheType` or `field_name: Annotated[TheType, ...]`) as well as `Annotated` metadata (used as `field_name: Annotated[int, SomeMetadata]`) can modify or override the generated schema by implementing `__get_pydantic_core_schema__`. This method receives two positional arguments: 1. The type annotation that corresponds to this type (so in the case of `TheType[T][int]` it would be `TheType[int]`). 2. A handler/callback to call the next implementer of `__get_pydantic_core_schema__`. The handler system works just like [*wrap* field validators](validators.md#field-wrap-validator). In this case the input is the type and the output is a `core_schema`. Here is an example of a custom type that *overrides* the generated `core_schema`: ```python from dataclasses import dataclass from typing import Any from pydantic_core import core_schema from pydantic import BaseModel, GetCoreSchemaHandler @dataclass class CompressedString: dictionary: dict[int, str] text: list[int] def build(self) -> str: return ' '.join([self.dictionary[key] for key in self.text]) @classmethod def __get_pydantic_core_schema__( cls, source: type[Any], handler: GetCoreSchemaHandler ) -> core_schema.CoreSchema: assert source is CompressedString return core_schema.no_info_after_validator_function( cls._validate, core_schema.str_schema(), serialization=core_schema.plain_serializer_function_ser_schema( cls._serialize, info_arg=False, return_schema=core_schema.str_schema(), ), ) @staticmethod def _validate(value: str) -> 'CompressedString': inverse_dictionary: dict[str, int] = {} text: list[int] = [] for word in value.split(' '): if word not in inverse_dictionary: inverse_dictionary[word] = len(inverse_dictionary) text.append(inverse_dictionary[word]) return CompressedString( {v: k for k, v in inverse_dictionary.items()}, text ) @staticmethod def _serialize(value: 'CompressedString') -> str: return value.build() class MyModel(BaseModel): value: CompressedString print(MyModel.model_json_schema()) """ { 'properties': {'value': {'title': 'Value', 'type': 'string'}}, 'required': ['value'], 'title': 'MyModel', 'type': 'object', } """ print(MyModel(value='fox fox fox dog fox')) """ value = CompressedString(dictionary={0: 'fox', 1: 'dog'}, text=[0, 0, 0, 1, 0]) """ print(MyModel(value='fox fox fox dog fox').model_dump(mode='json')) #> {'value': 'fox fox fox dog fox'} ``` Since Pydantic would not know how to generate a schema for `CompressedString`, if you call `handler(source)` in its `__get_pydantic_core_schema__` method you would get a `pydantic.errors.PydanticSchemaGenerationError` error. This will be the case for most custom types, so you almost never want to call into `handler` for custom types. The process for `Annotated` metadata is much the same except that you can generally call into `handler` to have Pydantic handle generating the schema. ```python from collections.abc import Sequence from dataclasses import dataclass from typing import Annotated, Any from pydantic_core import core_schema from pydantic import BaseModel, GetCoreSchemaHandler, ValidationError @dataclass class RestrictCharacters: alphabet: Sequence[str] def __get_pydantic_core_schema__( self, source: type[Any], handler: GetCoreSchemaHandler ) -> core_schema.CoreSchema: if not self.alphabet: raise ValueError('Alphabet may not be empty') schema = handler( source ) # get the CoreSchema from the type / inner constraints if schema['type'] != 'str': raise TypeError('RestrictCharacters can only be applied to strings') return core_schema.no_info_after_validator_function( self.validate, schema, ) def validate(self, value: str) -> str: if any(c not in self.alphabet for c in value): raise ValueError( f'{value!r} is not restricted to {self.alphabet!r}' ) return value class MyModel(BaseModel): value: Annotated[str, RestrictCharacters('ABC')] print(MyModel.model_json_schema()) """ { 'properties': {'value': {'title': 'Value', 'type': 'string'}}, 'required': ['value'], 'title': 'MyModel', 'type': 'object', } """ print(MyModel(value='CBA')) #> value='CBA' try: MyModel(value='XYZ') except ValidationError as e: print(e) """ 1 validation error for MyModel value Value error, 'XYZ' is not restricted to 'ABC' [type=value_error, input_value='XYZ', input_type=str] """ ``` So far we have been wrapping the schema, but if you just want to *modify* it or *ignore* it you can as well. To modify the schema, first call the handler, then mutate the result: ```python from typing import Annotated, Any from pydantic_core import ValidationError, core_schema from pydantic import BaseModel, GetCoreSchemaHandler class SmallString: def __get_pydantic_core_schema__( self, source: type[Any], handler: GetCoreSchemaHandler, ) -> core_schema.CoreSchema: schema = handler(source) assert schema['type'] == 'str' schema['max_length'] = 10 # modify in place return schema class MyModel(BaseModel): value: Annotated[str, SmallString()] try: MyModel(value='too long!!!!!') except ValidationError as e: print(e) """ 1 validation error for MyModel value String should have at most 10 characters [type=string_too_long, input_value='too long!!!!!', input_type=str] """ ``` !!! tip Note that you *must* return a schema, even if you are just mutating it in place. To override the schema completely, do not call the handler and return your own `CoreSchema`: ```python from typing import Annotated, Any from pydantic_core import ValidationError, core_schema from pydantic import BaseModel, GetCoreSchemaHandler class AllowAnySubclass: def __get_pydantic_core_schema__( self, source: type[Any], handler: GetCoreSchemaHandler ) -> core_schema.CoreSchema: # we can't call handler since it will fail for arbitrary types def validate(value: Any) -> Any: if not isinstance(value, source): raise ValueError( f'Expected an instance of {source}, got an instance of {type(value)}' ) return value return core_schema.no_info_plain_validator_function(validate) class Foo: pass class Model(BaseModel): f: Annotated[Foo, AllowAnySubclass()] print(Model(f=Foo())) #> f=<__main__.Foo object at 0x0123456789ab> class NotFoo: pass try: Model(f=NotFoo()) except ValidationError as e: print(e) """ 1 validation error for Model f Value error, Expected an instance of , got an instance of [type=value_error, input_value=<__main__.NotFoo object at 0x0123456789ab>, input_type=NotFoo] """ ``` ### Implementing `__get_pydantic_json_schema__` You can also implement `__get_pydantic_json_schema__` to modify or override the generated json schema. Modifying this method only affects the JSON schema - it doesn't affect the core schema, which is used for validation and serialization. Here's an example of modifying the generated JSON schema: ```python {output="json"} import json from typing import Any from pydantic_core import core_schema as cs from pydantic import GetCoreSchemaHandler, GetJsonSchemaHandler, TypeAdapter from pydantic.json_schema import JsonSchemaValue class Person: name: str age: int def __init__(self, name: str, age: int): self.name = name self.age = age @classmethod def __get_pydantic_core_schema__( cls, source_type: Any, handler: GetCoreSchemaHandler ) -> cs.CoreSchema: return cs.typed_dict_schema( { 'name': cs.typed_dict_field(cs.str_schema()), 'age': cs.typed_dict_field(cs.int_schema()), }, ) @classmethod def __get_pydantic_json_schema__( cls, core_schema: cs.CoreSchema, handler: GetJsonSchemaHandler ) -> JsonSchemaValue: json_schema = handler(core_schema) json_schema = handler.resolve_ref_schema(json_schema) json_schema['examples'] = [ { 'name': 'John Doe', 'age': 25, } ] json_schema['title'] = 'Person' return json_schema print(json.dumps(TypeAdapter(Person).json_schema(), indent=2)) """ { "examples": [ { "age": 25, "name": "John Doe" } ], "properties": { "name": { "title": "Name", "type": "string" }, "age": { "title": "Age", "type": "integer" } }, "required": [ "name", "age" ], "title": "Person", "type": "object" } """ ``` ### Using `field_title_generator` The `field_title_generator` parameter can be used to programmatically generate the title for a field based on its name and info. This is similar to the field level `field_title_generator`, but the `ConfigDict` option will be applied to all fields of the class. See the following example: ```python import json from pydantic import BaseModel, ConfigDict class Person(BaseModel): model_config = ConfigDict( field_title_generator=lambda field_name, field_info: field_name.upper() ) name: str age: int print(json.dumps(Person.model_json_schema(), indent=2)) """ { "properties": { "name": { "title": "NAME", "type": "string" }, "age": { "title": "AGE", "type": "integer" } }, "required": [ "name", "age" ], "title": "Person", "type": "object" } """ ``` ### Using `model_title_generator` The `model_title_generator` config option is similar to the `field_title_generator` option, but it applies to the title of the model itself, and accepts the model class as input. See the following example: ```python import json from pydantic import BaseModel, ConfigDict def make_title(model: type) -> str: return f'Title-{model.__name__}' class Person(BaseModel): model_config = ConfigDict(model_title_generator=make_title) name: str age: int print(json.dumps(Person.model_json_schema(), indent=2)) """ { "properties": { "name": { "title": "Name", "type": "string" }, "age": { "title": "Age", "type": "integer" } }, "required": [ "name", "age" ], "title": "Title-Person", "type": "object" } """ ``` ## JSON schema types Types, custom field types, and constraints (like `max_length`) are mapped to the corresponding spec formats in the following priority order (when there is an equivalent available): 1. [JSON Schema Core](https://json-schema.org/draft/2020-12/json-schema-core) 2. [JSON Schema Validation](https://json-schema.org/draft/2020-12/json-schema-validation) 3. [OpenAPI Data Types](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#data-types) 4. The standard `format` JSON field is used to define Pydantic extensions for more complex `string` sub-types. The field schema mapping from Python or Pydantic to JSON schema is done as follows: {{ schema_mappings_table }} ## Top-level schema generation You can also generate a top-level JSON schema that only includes a list of models and related sub-models in its `$defs`: ```python {output="json"} import json from pydantic import BaseModel from pydantic.json_schema import models_json_schema class Foo(BaseModel): a: str = None class Model(BaseModel): b: Foo class Bar(BaseModel): c: int _, top_level_schema = models_json_schema( [(Model, 'validation'), (Bar, 'validation')], title='My Schema' ) print(json.dumps(top_level_schema, indent=2)) """ { "$defs": { "Bar": { "properties": { "c": { "title": "C", "type": "integer" } }, "required": [ "c" ], "title": "Bar", "type": "object" }, "Foo": { "properties": { "a": { "default": null, "title": "A", "type": "string" } }, "title": "Foo", "type": "object" }, "Model": { "properties": { "b": { "$ref": "#/$defs/Foo" } }, "required": [ "b" ], "title": "Model", "type": "object" } }, "title": "My Schema" } """ ``` ## Customizing the JSON Schema Generation Process ??? api "API Documentation" [`pydantic.json_schema`][pydantic.json_schema.GenerateJsonSchema]
If you need custom schema generation, you can use a `schema_generator`, modifying the [`GenerateJsonSchema`][pydantic.json_schema.GenerateJsonSchema] class as necessary for your application. The various methods that can be used to produce JSON schema accept a keyword argument `schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema`, and you can pass your custom subclass to these methods in order to use your own approach to generating JSON schema. `GenerateJsonSchema` implements the translation of a type's `pydantic-core` schema into a JSON schema. By design, this class breaks the JSON schema generation process into smaller methods that can be easily overridden in subclasses to modify the "global" approach to generating JSON schema. ```python from pydantic import BaseModel from pydantic.json_schema import GenerateJsonSchema class MyGenerateJsonSchema(GenerateJsonSchema): def generate(self, schema, mode='validation'): json_schema = super().generate(schema, mode=mode) json_schema['title'] = 'Customize title' json_schema['$schema'] = self.schema_dialect return json_schema class MyModel(BaseModel): x: int print(MyModel.model_json_schema(schema_generator=MyGenerateJsonSchema)) """ { 'properties': {'x': {'title': 'X', 'type': 'integer'}}, 'required': ['x'], 'title': 'Customize title', 'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', } """ ``` Below is an approach you can use to exclude any fields from the schema that don't have valid json schemas: ```python from typing import Callable from pydantic_core import PydanticOmit, core_schema from pydantic import BaseModel from pydantic.json_schema import GenerateJsonSchema, JsonSchemaValue class MyGenerateJsonSchema(GenerateJsonSchema): def handle_invalid_for_json_schema( self, schema: core_schema.CoreSchema, error_info: str ) -> JsonSchemaValue: raise PydanticOmit def example_callable(): return 1 class Example(BaseModel): name: str = 'example' function: Callable = example_callable instance_example = Example() validation_schema = instance_example.model_json_schema( schema_generator=MyGenerateJsonSchema, mode='validation' ) print(validation_schema) """ { 'properties': { 'name': {'default': 'example', 'title': 'Name', 'type': 'string'} }, 'title': 'Example', 'type': 'object', } """ ``` ### JSON schema sorting By default, Pydantic recursively sorts JSON schemas by alphabetically sorting keys. Notably, Pydantic skips sorting the values of the `properties` key, to preserve the order of the fields as they were defined in the model. If you would like to customize this behavior, you can override the `sort` method in your custom `GenerateJsonSchema` subclass. The below example uses a no-op `sort` method to disable sorting entirely, which is reflected in the preserved order of the model fields and `json_schema_extra` keys: ```python import json from typing import Optional from pydantic import BaseModel, Field from pydantic.json_schema import GenerateJsonSchema, JsonSchemaValue class MyGenerateJsonSchema(GenerateJsonSchema): def sort( self, value: JsonSchemaValue, parent_key: Optional[str] = None ) -> JsonSchemaValue: """No-op, we don't want to sort schema values at all.""" return value class Bar(BaseModel): c: str b: str a: str = Field(json_schema_extra={'c': 'hi', 'b': 'hello', 'a': 'world'}) json_schema = Bar.model_json_schema(schema_generator=MyGenerateJsonSchema) print(json.dumps(json_schema, indent=2)) """ { "type": "object", "properties": { "c": { "type": "string", "title": "C" }, "b": { "type": "string", "title": "B" }, "a": { "type": "string", "c": "hi", "b": "hello", "a": "world", "title": "A" } }, "required": [ "c", "b", "a" ], "title": "Bar" } """ ``` ## Customizing the `$ref`s in JSON Schema The format of `$ref`s can be altered by calling [`model_json_schema()`][pydantic.main.BaseModel.model_json_schema] or [`model_dump_json()`][pydantic.main.BaseModel.model_dump_json] with the `ref_template` keyword argument. The definitions are always stored under the key `$defs`, but a specified prefix can be used for the references. This is useful if you need to extend or modify the JSON schema default definitions location. For example, with OpenAPI: ```python {output="json"} import json from pydantic import BaseModel from pydantic.type_adapter import TypeAdapter class Foo(BaseModel): a: int class Model(BaseModel): a: Foo adapter = TypeAdapter(Model) print( json.dumps( adapter.json_schema(ref_template='#/components/schemas/{model}'), indent=2, ) ) """ { "$defs": { "Foo": { "properties": { "a": { "title": "A", "type": "integer" } }, "required": [ "a" ], "title": "Foo", "type": "object" } }, "properties": { "a": { "$ref": "#/components/schemas/Foo" } }, "required": [ "a" ], "title": "Model", "type": "object" } """ ``` ## Miscellaneous Notes on JSON Schema Generation * The JSON schema for `Optional` fields indicates that the value `null` is allowed. * The `Decimal` type is exposed in JSON schema (and serialized) as a string. * Since the `namedtuple` type doesn't exist in JSON, a model's JSON schema does not preserve `namedtuple`s as `namedtuple`s. * Sub-models used are added to the `$defs` JSON attribute and referenced, as per the spec. * Sub-models with modifications (via the `Field` class) like a custom title, description, or default value, are recursively included instead of referenced. * The `description` for models is taken from either the docstring of the class or the argument `description` to the `Field` class. * The schema is generated by default using aliases as keys, but it can be generated using model property names instead by calling [`model_json_schema()`][pydantic.main.BaseModel.model_json_schema] or [`model_dump_json()`][pydantic.main.BaseModel.model_dump_json] with the `by_alias=False` keyword argument. pydantic-pydantic-ba0aa01/docs/concepts/models.md000066400000000000000000001635461517143232300222000ustar00rootroot00000000000000??? api "API Documentation" [`pydantic.main.BaseModel`][pydantic.main.BaseModel]
One of the primary ways of defining schema in Pydantic is via models. Models are simply classes which inherit from [`BaseModel`][pydantic.main.BaseModel] and define fields as annotated attributes. You can think of models as similar to structs in languages like C, or as the requirements of a single endpoint in an API. Models share many similarities with Python's [dataclasses][dataclasses], but have been designed with some subtle-yet-important differences that streamline certain workflows related to validation, serialization, and JSON schema generation. You can find more discussion of this in the [Dataclasses](dataclasses.md) section of the docs. Untrusted data can be passed to a model and, after parsing and validation, Pydantic guarantees that the fields of the resultant model instance will conform to the field types defined on the model. !!! note "Validation — a *deliberate* misnomer"

TL;DR

We use the term "validation" to refer to the process of instantiating a model (or other type) that adheres to specified types and constraints. This task, which Pydantic is well known for, is most widely recognized as "validation" in colloquial terms, even though in other contexts the term "validation" may be more restrictive. ---

The long version

The potential confusion around the term "validation" arises from the fact that, strictly speaking, Pydantic's primary focus doesn't align precisely with the dictionary definition of "validation": >

validation

> _noun_ > the action of checking or proving the validity or accuracy of something. In Pydantic, the term "validation" refers to the process of instantiating a model (or other type) that adheres to specified types and constraints. Pydantic guarantees the types and constraints of the output, not the input data. This distinction becomes apparent when considering that Pydantic's `ValidationError` is raised when data cannot be successfully parsed into a model instance. While this distinction may initially seem subtle, it holds practical significance. In some cases, "validation" goes beyond just model creation, and can include the copying and coercion of data. This can involve copying arguments passed to the constructor in order to perform coercion to a new type without mutating the original input data. For a more in-depth understanding of the implications for your usage, refer to the [Data Conversion](#data-conversion) and [Attribute Copies](#attribute-copies) sections below. In essence, Pydantic's primary goal is to assure that the resulting structure post-processing (termed "validation") precisely conforms to the applied type hints. Given the widespread adoption of "validation" as the colloquial term for this process, we will consistently use it in our documentation. While the terms "parse" and "validation" were previously used interchangeably, moving forward, we aim to exclusively employ "validate", with "parse" reserved specifically for discussions related to [JSON parsing](../concepts/json.md). ## Basic model usage !!! note Pydantic relies heavily on the existing Python typing constructs to define models. If you are not familiar with those, the following resources can be useful: * The [Type System Guides](https://typing.readthedocs.io/en/latest/guides/index.html) * The [mypy documentation](https://mypy.readthedocs.io/en/latest/) ```python {group="basic-model"} from pydantic import BaseModel, ConfigDict class User(BaseModel): id: int name: str = 'Jane Doe' model_config = ConfigDict(str_max_length=10) # (1)! ``` 1. Pydantic models support a variety of [configuration values](./config.md) (see [here][pydantic.ConfigDict] for the available configuration values). In this example, `User` is a model with two fields: * `id`, which is an integer (defined using the [`int`][] type) and is required * `name`, which is a string (defined using the [`str`][] type) and is not required (it has a default value). The documentation on [types](./types.md) expands on the supported types. Fields can be customized in a number of ways using the [`Field()`][pydantic.Field] function. See the [documentation on fields](./fields.md) for more information. The model can then be instantiated: ```python {group="basic-model"} user = User(id='123') ``` `user` is an instance of `User`. Initialization of the object will perform all parsing and validation. If no [`ValidationError`][pydantic_core.ValidationError] exception is raised, you know the resulting model instance is valid. Fields of a model can be accessed as normal attributes of the `user` object: ```python {group="basic-model"} assert user.name == 'Jane Doe' # (1)! assert user.id == 123 # (2)! assert isinstance(user.id, int) ``` 1. `name` wasn't set when `user` was initialized, so the default value was used. The [`model_fields_set`][pydantic.BaseModel.model_fields_set] attribute can be inspected to check the field names explicitly set during instantiation. 2. Note that the string `'123'` was coerced to an integer and its value is `123`. More details on Pydantic's coercion logic can be found in the [data conversion](#data-conversion) section. The model instance can be serialized using the [`model_dump()`][pydantic.BaseModel.model_dump] method: ```python {group="basic-model"} assert user.model_dump() == {'id': 123, 'name': 'Jane Doe'} ``` Calling [dict][] on the instance will also provide a dictionary, but nested fields will not be recursively converted into dictionaries. [`model_dump()`][pydantic.BaseModel.model_dump] also provides numerous arguments to customize the serialization result. By default, models are mutable and field values can be changed through attribute assignment: ```python {group="basic-model"} user.id = 321 assert user.id == 321 ``` !!! warning When defining your models, watch out for naming collisions between your field name and its type annotation. For example, the following will not behave as expected and would yield a validation error: ```python {test="skip"} from typing import Optional from pydantic import BaseModel class Boo(BaseModel): int: Optional[int] = None m = Boo(int=123) # Will fail to validate. ``` Because of how Python evaluates [annotated assignment statements][annassign], the statement is equivalent to `int: None = None`, thus leading to a validation error. ### Model methods and properties The example above only shows the tip of the iceberg of what models can do. Model classes possess the following methods and attributes: * [`model_validate()`][pydantic.main.BaseModel.model_validate]: Validates the given object against the Pydantic model. See [Validating data](#validating-data). * [`model_validate_json()`][pydantic.main.BaseModel.model_validate_json]: Validates the given JSON data against the Pydantic model. See [Validating data](#validating-data). * [`model_construct()`][pydantic.main.BaseModel.model_construct]: Creates models without running validation. See [Creating models without validation](#creating-models-without-validation). * [`model_dump()`][pydantic.main.BaseModel.model_dump]: Returns a dictionary of the model's fields and values. See [Serialization](serialization.md#python-mode). * [`model_dump_json()`][pydantic.main.BaseModel.model_dump_json]: Returns a JSON string representation of [`model_dump()`][pydantic.main.BaseModel.model_dump]. See [Serialization](serialization.md#json-mode). * [`model_copy()`][pydantic.main.BaseModel.model_copy]: Returns a copy (by default, shallow copy) of the model. See [Model copy](#model-copy). * [`model_json_schema()`][pydantic.main.BaseModel.model_json_schema]: Returns a jsonable dictionary representing the model's JSON Schema. See [JSON Schema](json_schema.md). * [`model_fields`][pydantic.main.BaseModel.model_fields]: A mapping between field names and their definitions ([`FieldInfo`][pydantic.fields.FieldInfo] instances). * [`model_computed_fields`][pydantic.main.BaseModel.model_computed_fields]: A mapping between computed field names and their definitions ([`ComputedFieldInfo`][pydantic.fields.ComputedFieldInfo] instances). * [`model_parametrized_name()`][pydantic.main.BaseModel.model_parametrized_name]: Computes the class name for parametrizations of generic classes. * [`model_post_init()`][pydantic.main.BaseModel.model_post_init]: Performs additional actions after the model is instantiated and all field validators are applied. * [`model_rebuild()`][pydantic.main.BaseModel.model_rebuild]: Rebuilds the model schema, which also supports building recursive generic models. See [Rebuilding model schema](#rebuilding-model-schema). Model instances possess the following attributes: * [`model_extra`][pydantic.main.BaseModel.model_extra]: The extra fields set during validation. * [`model_fields_set`][pydantic.main.BaseModel.model_fields_set]: The set of fields which were explicitly provided when the model was initialized. !!! note See the API documentation of [`BaseModel`][pydantic.main.BaseModel] for the class definition including a full list of methods and attributes. !!! tip See [Changes to `pydantic.BaseModel`](../migration.md#changes-to-pydanticbasemodel) in the [Migration Guide](../migration.md) for details on changes from Pydantic V1. ## Data conversion Pydantic may cast input data to force it to conform to model field types, and in some cases this may result in a loss of information. For example: ```python from pydantic import BaseModel class Model(BaseModel): a: int b: float c: str print(Model(a=3.000, b='2.72', c=b'binary data').model_dump()) #> {'a': 3, 'b': 2.72, 'c': 'binary data'} ``` This is a deliberate decision of Pydantic, and is frequently the most useful approach. See [this issue](https://github.com/pydantic/pydantic/issues/578) for a longer discussion on the subject. Nevertheless, Pydantic provides a [strict mode](strict_mode.md), where no data conversion is performed. Values must be of the same type as the declared field type. This is also the case for collections. In most cases, you shouldn't make use of abstract container classes and just use a concrete type, such as [`list`][]: ```python from pydantic import BaseModel class Model(BaseModel): items: list[int] # (1)! print(Model(items=(1, 2, 3))) #> items=[1, 2, 3] ``` 1. In this case, you might be tempted to use the abstract [`Sequence`][collections.abc.Sequence] type to allow both lists and tuples. But Pydantic takes care of converting the tuple input to a list, so in most cases this isn't necessary. Besides, using these abstract types can also lead to [poor validation performance](./performance.md#sequence-vs-list-or-tuple-with-mapping-vs-dict), and in general using concrete container types will avoid unnecessary checks. [](){#extra-fields} ## Extra data By default, Pydantic models **won't error when you provide extra data**, and these values will simply be ignored: ```python from pydantic import BaseModel class Model(BaseModel): x: int m = Model(x=1, y='a') assert m.model_dump() == {'x': 1} ``` The [`extra`][pydantic.ConfigDict.extra] configuration value can be used to control this behavior: ```python from pydantic import BaseModel, ConfigDict class Model(BaseModel): x: int model_config = ConfigDict(extra='allow') m = Model(x=1, y='a') # (1)! assert m.model_dump() == {'x': 1, 'y': 'a'} assert m.__pydantic_extra__ == {'y': 'a'} ``` 1. If [`extra`][pydantic.ConfigDict.extra] was set to `'forbid'`, this would fail. The configuration can take three values: * `'ignore'`: Providing extra data is ignored (the default). * `'forbid'`: Providing extra data is not permitted. * `'allow'`: Providing extra data is allowed and stored in the `__pydantic_extra__` dictionary attribute. The `__pydantic_extra__` can explicitly be annotated to provide validation for extra fields. The validation methods (e.g. [`model_validate()`][pydantic.main.BaseModel.model_validate]) have an optional `extra` argument that will override the `extra` configuration value of the model for that validation call. For more details, refer to the [`extra`][pydantic.ConfigDict.extra] API documentation. Pydantic dataclasses also support extra data (see the [dataclass configuration](./dataclasses.md#dataclass-config) section). ## Nested models More complex hierarchical data structures can be defined using models themselves as types in annotations. ```python from typing import Optional from pydantic import BaseModel class Foo(BaseModel): count: int size: Optional[float] = None class Bar(BaseModel): apple: str = 'x' banana: str = 'y' class Spam(BaseModel): foo: Foo bars: list[Bar] m = Spam(foo={'count': 4}, bars=[{'apple': 'x1'}, {'apple': 'x2'}]) print(m) """ foo=Foo(count=4, size=None) bars=[Bar(apple='x1', banana='y'), Bar(apple='x2', banana='y')] """ print(m.model_dump()) """ { 'foo': {'count': 4, 'size': None}, 'bars': [{'apple': 'x1', 'banana': 'y'}, {'apple': 'x2', 'banana': 'y'}], } """ ``` Self-referencing models are supported. For more details, see the documentation related to [forward annotations](forward_annotations.md#self-referencing-or-recursive-models). ## Rebuilding model schema When you define a model class in your code, Pydantic will analyze the body of the class to collect a variety of information required to perform validation and serialization, gathered in a core schema. Notably, the model's type annotations are evaluated to understand the valid types for each field (more information can be found in the [Architecture](../internals/architecture.md) documentation). However, it might be the case that annotations refer to symbols not defined when the model class is being created. To circumvent this issue, the [`model_rebuild()`][pydantic.main.BaseModel.model_rebuild] method can be used: ```python from pydantic import BaseModel, PydanticUserError class Foo(BaseModel): x: 'Bar' # (1)! try: Foo.model_json_schema() except PydanticUserError as e: print(e) """ `Foo` is not fully defined; you should define `Bar`, then call `Foo.model_rebuild()`. For further information visit https://errors.pydantic.dev/2/u/class-not-fully-defined """ class Bar(BaseModel): pass Foo.model_rebuild() print(Foo.model_json_schema()) """ { '$defs': {'Bar': {'properties': {}, 'title': 'Bar', 'type': 'object'}}, 'properties': {'x': {'$ref': '#/$defs/Bar'}}, 'required': ['x'], 'title': 'Foo', 'type': 'object', } """ ``` 1. `Bar` is not yet defined when the `Foo` class is being created. For this reason, a [forward annotation](forward_annotations.md) is being used. Pydantic tries to determine when this is necessary automatically and error if it wasn't done, but you may want to call [`model_rebuild()`][pydantic.main.BaseModel.model_rebuild] proactively when dealing with recursive models or generics. In V2, [`model_rebuild()`][pydantic.main.BaseModel.model_rebuild] replaced `update_forward_refs()` from V1. There are some slight differences with the new behavior. The biggest change is that when calling [`model_rebuild()`][pydantic.main.BaseModel.model_rebuild] on the outermost model, it builds a core schema used for validation of the whole model (nested models and all), so all types at all levels need to be ready before [`model_rebuild()`][pydantic.main.BaseModel.model_rebuild] is called. ## Validating data Pydantic can validate data in three different modes: *Python*, *JSON* and *strings*. The *Python* mode gets used when using: * The `__init__()` model constructor. Field values must be provided using keyword arguments. * [`model_validate()`][pydantic.main.BaseModel.model_validate]: data can be provided either as a dictionary, or as a model instance (by default, instances are assumed to be valid; see the [`revalidate_instances`][pydantic.ConfigDict.revalidate_instances] setting). [Arbitrary objects](#arbitrary-class-instances) can also be provided if explicitly enabled. The *JSON* and *strings* modes can be used with dedicated methods: * [`model_validate_json()`][pydantic.main.BaseModel.model_validate_json]: data is validated as a JSON string or `bytes` object. If your incoming data is a JSON payload, this is generally considered faster (instead of manually parsing the data as a dictionary). Learn more about JSON parsing in the [JSON](../concepts/json.md) documentation. * [`model_validate_strings()`][pydantic.main.BaseModel.model_validate_strings]: data is validated as a dictionary (can be nested) with string keys and values and validates the data in JSON mode so that said strings can be coerced into the correct types. Compared to using the model constructor, it is possible to control several validation parameters when using the `model_validate_*()` methods ([strictness](./strict_mode.md), [extra data](#extra-data), [validation context](./validators.md#validation-context), etc.). !!! note Depending on the types and model configuration involved, the *Python* and *JSON* modes may have different validation behavior (e.g. with [strictness](./strict_mode.md)). If you have data coming from a non-JSON source, but want the same validation behavior and errors you'd get from the *JSON* mode, our recommendation for now is to either dump your data to JSON (e.g. using [`json.dumps()`][json.dumps]), or use [`model_validate_strings()`][pydantic.main.BaseModel.model_validate_strings] if the data takes the form of a (potentially nested) dictionary with string keys and values. Progress for this feature can be tracked in [this issue](https://github.com/pydantic/pydantic/issues/11154). ```python from datetime import datetime from typing import Optional from pydantic import BaseModel, ValidationError class User(BaseModel): id: int name: str = 'John Doe' signup_ts: Optional[datetime] = None m = User.model_validate({'id': 123, 'name': 'James'}) print(m) #> id=123 name='James' signup_ts=None try: m = User.model_validate_json('{"id": 123, "name": 123}') except ValidationError as e: print(e) """ 1 validation error for User name Input should be a valid string [type=string_type, input_value=123, input_type=int] """ m = User.model_validate_strings({'id': '123', 'name': 'James'}) print(m) #> id=123 name='James' signup_ts=None m = User.model_validate_strings( {'id': '123', 'name': 'James', 'signup_ts': '2024-04-01T12:00:00'} ) print(m) #> id=123 name='James' signup_ts=datetime.datetime(2024, 4, 1, 12, 0) try: m = User.model_validate_strings( {'id': '123', 'name': 'James', 'signup_ts': '2024-04-01'}, strict=True ) except ValidationError as e: print(e) """ 1 validation error for User signup_ts Input should be a valid datetime, invalid datetime separator, expected `T`, `t`, `_` or space [type=datetime_parsing, input_value='2024-04-01', input_type=str] """ ``` ### Creating models without validation Pydantic also provides the [`model_construct()`][pydantic.main.BaseModel.model_construct] method, which allows models to be created **without validation**. This can be useful in at least a few cases: * when working with complex data that is already known to be valid (for performance reasons) * when one or more of the validator functions are non-idempotent * when one or more of the validator functions have side effects that you don't want to be triggered. !!! warning [`model_construct()`][pydantic.main.BaseModel.model_construct] does not do any validation, meaning it can create models which are invalid. **You should only ever use the [`model_construct()`][pydantic.main.BaseModel.model_construct] method with data which has already been validated, or that you definitely trust.** !!! note In Pydantic V2, the performance gap between validation (either with direct instantiation or the `model_validate*` methods) and [`model_construct()`][pydantic.main.BaseModel.model_construct] has been narrowed considerably. For simple models, going with validation may even be faster. If you are using [`model_construct()`][pydantic.main.BaseModel.model_construct] for performance reasons, you may want to profile your use case before assuming it is actually faster. Note that for [root models](#rootmodel-and-custom-root-types), the root value can be passed to [`model_construct()`][pydantic.main.BaseModel.model_construct] positionally, instead of using a keyword argument. Here are some additional notes on the behavior of [`model_construct()`][pydantic.main.BaseModel.model_construct]: * When we say "no validation is performed" — this includes converting dictionaries to model instances. So if you have a field referring to a model type, you will need to convert the inner dictionary to a model yourself. * If you do not pass keyword arguments for fields with defaults, the default values will still be used. * For models with private attributes, the `__pydantic_private__` dictionary will be populated the same as it would be when creating the model with validation. * No `__init__` method from the model or any of its parent classes will be called, even when a custom `__init__` method is defined. !!! note "On [extra data](#extra-data) behavior with [`model_construct()`][pydantic.main.BaseModel.model_construct]" * For models with [`extra`][pydantic.ConfigDict.extra] set to `'allow'`, data not corresponding to fields will be correctly stored in the `__pydantic_extra__` dictionary and saved to the model's `__dict__` attribute. * For models with [`extra`][pydantic.ConfigDict.extra] set to `'ignore'`, data not corresponding to fields will be ignored — that is, not stored in `__pydantic_extra__` or `__dict__` on the instance. * Unlike when instantiating the model with validation, a call to [`model_construct()`][pydantic.main.BaseModel.model_construct] with [`extra`][pydantic.ConfigDict.extra] set to `'forbid'` doesn't raise an error in the presence of data not corresponding to fields. Rather, said input data is simply ignored. ### Defining a custom `__init__()` Pydantic provides a default `__init__()` implementation for Pydantic models, that is called *only* when using the model constructor (and not with the `model_validate_*()` methods). This implementation delegates validation to `pydantic-core`. However, it is possible to define a custom `__init__()` on your models. In this case, it will be called unconditionally from all the [validation methods](#validating-data), without performing validation (and so you should call `super().__init__(**kwargs)` in your implementation). Defining a custom `__init__()` is not recommended, as all the validation parameters ([strictness](./strict_mode.md), [extra data behavior](#extra-data), [validation context](./validators.md#validation-context)) will be lost. If you need to perform actions after the model was initialized, you can make use of *after* [field](./validators.md#field-after-validator) or [model](./validators.md#model-after-validator) validators, or define a [`model_post_init()`][pydantic.main.BaseModel.model_post_init] implementation: ```python import logging from typing import Any from pydantic import BaseModel class MyModel(BaseModel): id: int def model_post_init(self, context: Any) -> None: logging.info("Model initialized with id %d", self.id) ``` ## Error handling Pydantic will raise a [`ValidationError`][pydantic_core.ValidationError] exception whenever it finds an error in the data it's validating. A single exception will be raised regardless of the number of errors found, and that validation error will contain information about all of the errors and how they happened. See [Error Handling](../errors/errors.md) for details on standard and custom errors. As a demonstration: ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): list_of_ints: list[int] a_float: float data = { 'list_of_ints': ['1', 2, 'bad'], 'a_float': 'not a float', } try: Model(**data) except ValidationError as e: print(e) """ 2 validation errors for Model list_of_ints.2 Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='bad', input_type=str] a_float Input should be a valid number, unable to parse string as a number [type=float_parsing, input_value='not a float', input_type=str] """ ``` ## Arbitrary class instances (Formerly known as "ORM Mode"/`from_orm()`). When using the [`model_validate()`][pydantic.main.BaseModel.model_validate] method, Pydantic can also validate arbitrary objects, by getting attributes on the object corresponding the field names. One common application of this functionality is integration with object-relational mappings (ORMs). This feature need to be manually enabled, either by setting the [`from_attributes`][pydantic.config.ConfigDict.from_attributes] configuration value, or by using the `from_attributes` parameter on [`model_validate()`][pydantic.main.BaseModel.model_validate]. The example here uses [SQLAlchemy](https://www.sqlalchemy.org/), but the same approach should work for any ORM. ```python from typing import Annotated from sqlalchemy import ARRAY, String from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column from pydantic import BaseModel, ConfigDict, StringConstraints class Base(DeclarativeBase): pass class CompanyOrm(Base): __tablename__ = 'companies' id: Mapped[int] = mapped_column(primary_key=True, nullable=False) public_key: Mapped[str] = mapped_column( String(20), index=True, nullable=False, unique=True ) domains: Mapped[list[str]] = mapped_column(ARRAY(String(255))) class CompanyModel(BaseModel): model_config = ConfigDict(from_attributes=True) id: int public_key: Annotated[str, StringConstraints(max_length=20)] domains: list[Annotated[str, StringConstraints(max_length=255)]] co_orm = CompanyOrm( id=123, public_key='foobar', domains=['example.com', 'foobar.com'], ) print(co_orm) #> <__main__.CompanyOrm object at 0x0123456789ab> co_model = CompanyModel.model_validate(co_orm) print(co_model) #> id=123 public_key='foobar' domains=['example.com', 'foobar.com'] ``` ### Nested attributes When using attributes to validate models, model instances will be created from both top-level attributes and deeper-nested attributes as appropriate. Here is an example demonstrating the principle: ```python from pydantic import BaseModel, ConfigDict class PetCls: def __init__(self, *, name: str) -> None: self.name = name class PersonCls: def __init__(self, *, name: str, pets: list[PetCls]) -> None: self.name = name self.pets = pets class Pet(BaseModel): model_config = ConfigDict(from_attributes=True) name: str class Person(BaseModel): model_config = ConfigDict(from_attributes=True) name: str pets: list[Pet] bones = PetCls(name='Bones') orion = PetCls(name='Orion') anna = PersonCls(name='Anna', pets=[bones, orion]) anna_model = Person.model_validate(anna) print(anna_model) #> name='Anna' pets=[Pet(name='Bones'), Pet(name='Orion')] ``` ## Model copy ??? api "API Documentation" [`pydantic.main.BaseModel.model_copy`][pydantic.main.BaseModel.model_copy]
The [`model_copy()`][pydantic.BaseModel.model_copy] method allows models to be duplicated (with optional updates), which is particularly useful when working with frozen models. ```python from pydantic import BaseModel class BarModel(BaseModel): whatever: int class FooBarModel(BaseModel): banana: float foo: str bar: BarModel m = FooBarModel(banana=3.14, foo='hello', bar={'whatever': 123}) print(m.model_copy(update={'banana': 0})) #> banana=0 foo='hello' bar=BarModel(whatever=123) # normal copy gives the same object reference for bar: print(id(m.bar) == id(m.model_copy().bar)) #> True # deep copy gives a new object reference for `bar`: print(id(m.bar) == id(m.model_copy(deep=True).bar)) #> False ``` ## Generic models Pydantic supports the creation of generic models to make it easier to reuse a common model structure. Both the new [type parameter syntax][type-params] (introduced by [PEP 695](https://peps.python.org/pep-0695/) in Python 3.12) and the old syntax are supported (refer to [the Python documentation](https://docs.python.org/3/library/typing.html#building-generic-types-and-type-aliases) for more details). Here is an example using a generic Pydantic model to create an easily-reused HTTP response payload wrapper: === "Python 3.9 and above" ```python {upgrade="skip"} from typing import Generic, TypeVar from pydantic import BaseModel, ValidationError DataT = TypeVar('DataT') # (1)! class DataModel(BaseModel): number: int class Response(BaseModel, Generic[DataT]): # (2)! data: DataT # (3)! print(Response[int](data=1)) #> data=1 print(Response[str](data='value')) #> data='value' print(Response[str](data='value').model_dump()) #> {'data': 'value'} data = DataModel(number=1) print(Response[DataModel](data=data).model_dump()) #> {'data': {'number': 1}} try: Response[int](data='value') except ValidationError as e: print(e) """ 1 validation error for Response[int] data Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='value', input_type=str] """ ``` 1. Declare one or more [type variables][typing.TypeVar] to use to parameterize your model. 2. Declare a Pydantic model that inherits from [`BaseModel`][pydantic.BaseModel] and [`typing.Generic`][] (in this specific order), and add the list of type variables you declared previously as parameters to the [`Generic`][typing.Generic] parent. 3. Use the type variables as annotations where you will want to replace them with other types. === "Python 3.12 and above (new syntax)" ```python {requires="3.12" upgrade="skip" lint="skip"} from pydantic import BaseModel, ValidationError class DataModel(BaseModel): number: int class Response[DataT](BaseModel): # (1)! data: DataT # (2)! print(Response[int](data=1)) #> data=1 print(Response[str](data='value')) #> data='value' print(Response[str](data='value').model_dump()) #> {'data': 'value'} data = DataModel(number=1) print(Response[DataModel](data=data).model_dump()) #> {'data': {'number': 1}} try: Response[int](data='value') except ValidationError as e: print(e) """ 1 validation error for Response[int] data Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='value', input_type=str] """ ``` 1. Declare a Pydantic model and add the list of type variables as type parameters. 2. Use the type variables as annotations where you will want to replace them with other types. /// version-added | v2.11 Full support for the [type parameter syntax][type-params] and [type variable defaults](https://typing.python.org/en/latest/spec/generics.html#type-parameter-defaults). /// !!! warning When parametrizing a model with a concrete type, Pydantic **does not** validate that the provided type is [assignable to the type variable][spec-typevars-bound] if it has an upper bound. [spec-typevars-bound]: https://typing.readthedocs.io/en/latest/spec/generics.html#type-variables-with-an-upper-bound Any [configuration](./config.md), [validation](./validators.md) or [serialization](./serialization.md) logic set on the generic model will also be applied to the parametrized classes, in the same way as when inheriting from a model class. Any custom methods or attributes will also be inherited. Generic models also integrate properly with type checkers, so you get all the type checking you would expect if you were to declare a distinct type for each parametrization. !!! note Internally, Pydantic creates subclasses of the generic model at runtime when the generic model class is parametrized. These classes are cached, so there should be minimal overhead introduced by the use of generics models. To inherit from a generic model and preserve the fact that it is generic, the subclass must also inherit from [`Generic`][typing.Generic]: ```python from typing import Generic, TypeVar from pydantic import BaseModel TypeX = TypeVar('TypeX') class BaseClass(BaseModel, Generic[TypeX]): X: TypeX class ChildClass(BaseClass[TypeX], Generic[TypeX]): pass # Parametrize `TypeX` with `int`: print(ChildClass[int](X=1)) #> X=1 ``` You can also create a generic subclass of a model that partially or fully replaces the type variables in the superclass: ```python from typing import Generic, TypeVar from pydantic import BaseModel TypeX = TypeVar('TypeX') TypeY = TypeVar('TypeY') TypeZ = TypeVar('TypeZ') class BaseClass(BaseModel, Generic[TypeX, TypeY]): x: TypeX y: TypeY class ChildClass(BaseClass[int, TypeY], Generic[TypeY, TypeZ]): z: TypeZ # Parametrize `TypeY` with `str`: print(ChildClass[str, int](x='1', y='y', z='3')) #> x=1 y='y' z=3 ``` If the name of the concrete subclasses is important, you can also override the default name generation by overriding the [`model_parametrized_name()`][pydantic.main.BaseModel.model_parametrized_name] method: ```python from typing import Any, Generic, TypeVar from pydantic import BaseModel DataT = TypeVar('DataT') class Response(BaseModel, Generic[DataT]): data: DataT @classmethod def model_parametrized_name(cls, params: tuple[type[Any], ...]) -> str: return f'{params[0].__name__.title()}Response' print(repr(Response[int](data=1))) #> IntResponse(data=1) print(repr(Response[str](data='a'))) #> StrResponse(data='a') ``` You can use parametrized generic models as types in other models: ```python from typing import Generic, TypeVar from pydantic import BaseModel T = TypeVar('T') class ResponseModel(BaseModel, Generic[T]): content: T class Product(BaseModel): name: str price: float class Order(BaseModel): id: int product: ResponseModel[Product] product = Product(name='Apple', price=0.5) response = ResponseModel[Product](content=product) order = Order(id=1, product=response) print(repr(order)) """ Order(id=1, product=ResponseModel[Product](content=Product(name='Apple', price=0.5))) """ ``` Using the same type variable in nested models allows you to enforce typing relationships at different points in your model: ```python from typing import Generic, TypeVar from pydantic import BaseModel, ValidationError T = TypeVar('T') class InnerT(BaseModel, Generic[T]): inner: T class OuterT(BaseModel, Generic[T]): outer: T nested: InnerT[T] nested = InnerT[int](inner=1) print(OuterT[int](outer=1, nested=nested)) #> outer=1 nested=InnerT[int](inner=1) try: print(OuterT[int](outer='a', nested=InnerT(inner='a'))) # (1)! except ValidationError as e: print(e) """ 2 validation errors for OuterT[int] outer Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str] nested.inner Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str] """ ``` 1. The `OuterT` model is parametrized with `int`, but the data associated with the `T` annotations during validation is of type `str`, leading to validation errors. !!! warning While it may not raise an error, we strongly advise against using parametrized generics in [`isinstance()`](https://docs.python.org/3/library/functions.html#isinstance) checks. For example, you should not do `isinstance(my_model, MyGenericModel[int])`. However, it is fine to do `isinstance(my_model, MyGenericModel)` (note that, for standard generics, it would raise an error to do a subclass check with a parameterized generic class). If you need to perform [`isinstance()`](https://docs.python.org/3/library/functions.html#isinstance) checks against parametrized generics, you can do this by subclassing the parametrized generic class: ```python {test="skip" lint="skip"} class MyIntModel(MyGenericModel[int]): ... isinstance(my_model, MyIntModel) ``` ??? note "Implementation Details" When using nested generic models, Pydantic sometimes performs revalidation in an attempt to produce the most intuitive validation result. Specifically, if you have a field of type `GenericModel[SomeType]` and you validate data like `GenericModel[SomeCompatibleType]` against this field, we will inspect the data, recognize that the input data is sort of a "loose" subclass of `GenericModel`, and revalidate the contained `SomeCompatibleType` data. This adds some validation overhead, but makes things more intuitive for cases like that shown below. ```python from typing import Any, Generic, TypeVar from pydantic import BaseModel T = TypeVar('T') class GenericModel(BaseModel, Generic[T]): a: T class Model(BaseModel): inner: GenericModel[Any] print(repr(Model.model_validate(Model(inner=GenericModel[int](a=1))))) #> Model(inner=GenericModel[Any](a=1)) ``` Note, validation will still fail if you, for example are validating against `GenericModel[int]` and pass in an instance `GenericModel[str](a='not an int')`. It's also worth noting that this pattern will re-trigger any custom validation as well, like additional model validators and the like. Validators will be called once on the first pass, validating directly against `GenericModel[Any]`. That validation fails, as `GenericModel[int]` is not a subclass of `GenericModel[Any]`. This relates to the warning above about the complications of using parametrized generics in `isinstance()` and `issubclass()` checks. Then, the validators will be called again on the second pass, during more lax force-revalidation phase, which succeeds. To better understand this consequence, see below: ```python {test="skip"} from typing import Any, Generic, Self, TypeVar from pydantic import BaseModel, model_validator T = TypeVar('T') class GenericModel(BaseModel, Generic[T]): a: T @model_validator(mode='after') def validate_after(self: Self) -> Self: print('after validator running custom validation...') return self class Model(BaseModel): inner: GenericModel[Any] m = Model.model_validate(Model(inner=GenericModel[int](a=1))) #> after validator running custom validation... #> after validator running custom validation... print(repr(m)) #> Model(inner=GenericModel[Any](a=1)) ``` ### Validation of unparametrized type variables When leaving type variables unparametrized, Pydantic treats generic models similarly to how it treats built-in generic types like [`list`][] and [`dict`][]: * If the type variable is [bound](https://typing.readthedocs.io/en/latest/reference/generics.html#type-variables-with-upper-bounds) or [constrained](https://typing.readthedocs.io/en/latest/reference/generics.html#type-variables-with-constraints) to a specific type, it will be used. * If the type variable has a default type (as specified by [PEP 696](https://peps.python.org/pep-0696/)), it will be used. * For unbound or unconstrained type variables, Pydantic will fallback to [`Any`][typing.Any]. ```python from typing import Generic from typing_extensions import TypeVar from pydantic import BaseModel, ValidationError T = TypeVar('T') U = TypeVar('U', bound=int) V = TypeVar('V', default=str) class Model(BaseModel, Generic[T, U, V]): t: T u: U v: V print(Model(t='t', u=1, v='v')) #> t='t' u=1 v='v' try: Model(t='t', u='u', v=1) except ValidationError as exc: print(exc) """ 2 validation errors for Model u Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='u', input_type=str] v Input should be a valid string [type=string_type, input_value=1, input_type=int] """ ``` !!! warning In some cases, validation against an unparametrized generic model can lead to data loss. Specifically, if a subtype of the type variable upper bound, constraints, or default is being used and the model isn't explicitly parametrized, the resulting type **will not be** the one being provided: ```python from typing import Generic, TypeVar from pydantic import BaseModel ItemT = TypeVar('ItemT', bound='ItemBase') class ItemBase(BaseModel): ... class IntItem(ItemBase): value: int class ItemHolder(BaseModel, Generic[ItemT]): item: ItemT loaded_data = {'item': {'value': 1}} print(ItemHolder(**loaded_data)) # (1)! #> item=ItemBase() print(ItemHolder[IntItem](**loaded_data)) # (2)! #> item=IntItem(value=1) ``` 1. When the generic isn't parametrized, the input data is validated against the `ItemT` upper bound. Given that `ItemBase` has no fields, the `item` field information is lost. 2. In this case, the type variable is explicitly parametrized, so the input data is validated against the `IntItem` class. ### Serialization of unparametrized type variables The behavior of serialization differs when using type variables with [upper bounds](https://typing.readthedocs.io/en/latest/reference/generics.html#type-variables-with-upper-bounds), [constraints](https://typing.readthedocs.io/en/latest/reference/generics.html#type-variables-with-constraints), or a default value: If a Pydantic model is used in a type variable upper bound and the type variable is never parametrized, then Pydantic will use the upper bound for validation but treat the value as [`Any`][typing.Any] in terms of serialization: ```python from typing import Generic, TypeVar from pydantic import BaseModel class ErrorDetails(BaseModel): foo: str ErrorDataT = TypeVar('ErrorDataT', bound=ErrorDetails) class Error(BaseModel, Generic[ErrorDataT]): message: str details: ErrorDataT class MyErrorDetails(ErrorDetails): bar: str # serialized as Any error = Error( message='We just had an error', details=MyErrorDetails(foo='var', bar='var2'), ) assert error.model_dump() == { 'message': 'We just had an error', 'details': { 'foo': 'var', 'bar': 'var2', }, } # serialized using the concrete parametrization # note that `'bar': 'var2'` is missing error = Error[ErrorDetails]( message='We just had an error', details=ErrorDetails(foo='var'), ) assert error.model_dump() == { 'message': 'We just had an error', 'details': { 'foo': 'var', }, } ``` Here's another example of the above behavior, enumerating all permutations regarding bound specification and generic type parametrization: ```python from typing import Generic, TypeVar from pydantic import BaseModel TBound = TypeVar('TBound', bound=BaseModel) TNoBound = TypeVar('TNoBound') class IntValue(BaseModel): value: int class ItemBound(BaseModel, Generic[TBound]): item: TBound class ItemNoBound(BaseModel, Generic[TNoBound]): item: TNoBound item_bound_inferred = ItemBound(item=IntValue(value=3)) item_bound_explicit = ItemBound[IntValue](item=IntValue(value=3)) item_no_bound_inferred = ItemNoBound(item=IntValue(value=3)) item_no_bound_explicit = ItemNoBound[IntValue](item=IntValue(value=3)) # calling `print(x.model_dump())` on any of the above instances results in the following: #> {'item': {'value': 3}} ``` However, if [constraints](https://typing.readthedocs.io/en/latest/reference/generics.html#type-variables-with-constraints) or a default value (as per [PEP 696](https://peps.python.org/pep-0696/)) is being used, then the default type or constraints will be used for both validation and serialization if the type variable is not parametrized. You can override this behavior using [`SerializeAsAny`](./serialization.md#serializeasany-annotation): ```python from typing import Generic from typing_extensions import TypeVar from pydantic import BaseModel, SerializeAsAny class ErrorDetails(BaseModel): foo: str ErrorDataT = TypeVar('ErrorDataT', default=ErrorDetails) class Error(BaseModel, Generic[ErrorDataT]): message: str details: ErrorDataT class MyErrorDetails(ErrorDetails): bar: str # serialized using the default's serializer error = Error( message='We just had an error', details=MyErrorDetails(foo='var', bar='var2'), ) assert error.model_dump() == { 'message': 'We just had an error', 'details': { 'foo': 'var', }, } # If `ErrorDataT` was using an upper bound, `bar` would be present in `details`. class SerializeAsAnyError(BaseModel, Generic[ErrorDataT]): message: str details: SerializeAsAny[ErrorDataT] # serialized as Any error = SerializeAsAnyError( message='We just had an error', details=MyErrorDetails(foo='var', bar='baz'), ) assert error.model_dump() == { 'message': 'We just had an error', 'details': { 'foo': 'var', 'bar': 'baz', }, } ``` ## Dynamic model creation ??? api "API Documentation" [`pydantic.main.create_model`][pydantic.main.create_model]
There are some occasions where it is desirable to create a model using runtime information to specify the fields. Pydantic provides the [`create_model()`][pydantic.create_model] function to allow models to be created dynamically: ```python from pydantic import BaseModel, create_model DynamicFoobarModel = create_model('DynamicFoobarModel', foo=str, bar=(int, 123)) # Equivalent to: class StaticFoobarModel(BaseModel): foo: str bar: int = 123 ``` Field definitions are specified as keyword arguments, and should either be: * A single element, representing the type annotation of the field. * A two-tuple, the first element being the type and the second element the assigned value (either a default or the [`Field()`][pydantic.Field] function). /// version-changed | v2.11 When providing a single element for field definitions, any type can be used (previously, only an [`Annotated`][typing.Annotated] form could be provided). /// Here is a more advanced example: ```python from typing import Annotated from pydantic import BaseModel, Field, PrivateAttr, create_model DynamicModel = create_model( 'DynamicModel', foo=(str, Field(alias='FOO')), bar=Annotated[str, Field(description='Bar field')], _private=(int, PrivateAttr(default=1)), ) class StaticModel(BaseModel): foo: str = Field(alias='FOO') bar: Annotated[str, Field(description='Bar field')] _private: int = PrivateAttr(default=1) ``` The special keyword arguments `__config__` and `__base__` can be used to customize the new model. This includes extending a base model with extra fields. ```python from pydantic import BaseModel, create_model class FooModel(BaseModel): foo: str bar: int = 123 BarModel = create_model( 'BarModel', apple=(str, 'russet'), banana=(str, 'yellow'), __base__=FooModel, ) print(BarModel) #> print(BarModel.model_fields.keys()) #> dict_keys(['foo', 'bar', 'apple', 'banana']) ``` You can also add validators by passing a dictionary to the `__validators__` argument. ```python {rewrite_assert="false"} from pydantic import ValidationError, create_model, field_validator def alphanum(cls, v): assert v.isalnum(), 'must be alphanumeric' return v validators = { 'username_validator': field_validator('username')(alphanum) # (1)! } UserModel = create_model( 'UserModel', username=(str, ...), __validators__=validators ) user = UserModel(username='scolvin') print(user) #> username='scolvin' try: UserModel(username='scolvi%n') except ValidationError as e: print(e) """ 1 validation error for UserModel username Assertion failed, must be alphanumeric [type=assertion_error, input_value='scolvi%n', input_type=str] """ ``` 1. Make sure that the validators names do not clash with any of the field names as internally, Pydantic gathers all members into a namespace and mimics the normal creation of a class using the [`types` module utilities](https://docs.python.org/3/library/types.html#dynamic-type-creation). !!! note To pickle a dynamically created model: * the model must be defined globally * the `__module__` argument must be provided !!! warning This function may execute arbitrary code contained in field annotations, if string references need to be evaluated. See [Security implications of introspecting annotations](https://docs.python.org/3/library/annotationlib.html#annotationlib-security) for more information. See also: the [dynamic model example](../examples/dynamic_models.md), providing guidelines to derive an optional model from another one. ## `RootModel` and custom root types ??? api "API Documentation" [`pydantic.root_model.RootModel`][pydantic.root_model.RootModel]
Pydantic models can be defined with a "custom root type" by subclassing [`pydantic.RootModel`][pydantic.RootModel]. The root type can be any type supported by Pydantic, and is specified by the generic parameter to `RootModel`. The root value can be passed to the model `__init__` or [`model_validate`][pydantic.main.BaseModel.model_validate] via the first and only argument. Here's an example of how this works: ```python from pydantic import RootModel Pets = RootModel[list[str]] PetsByName = RootModel[dict[str, str]] print(Pets(['dog', 'cat'])) #> root=['dog', 'cat'] print(Pets(['dog', 'cat']).model_dump_json()) #> ["dog","cat"] print(Pets.model_validate(['dog', 'cat'])) #> root=['dog', 'cat'] print(Pets.model_json_schema()) """ {'items': {'type': 'string'}, 'title': 'RootModel[list[str]]', 'type': 'array'} """ print(PetsByName({'Otis': 'dog', 'Milo': 'cat'})) #> root={'Otis': 'dog', 'Milo': 'cat'} print(PetsByName({'Otis': 'dog', 'Milo': 'cat'}).model_dump_json()) #> {"Otis":"dog","Milo":"cat"} print(PetsByName.model_validate({'Otis': 'dog', 'Milo': 'cat'})) #> root={'Otis': 'dog', 'Milo': 'cat'} ``` If you want to access items in the `root` field directly or to iterate over the items, you can implement custom `__iter__` and `__getitem__` functions, as shown in the following example. ```python from pydantic import RootModel class Pets(RootModel): root: list[str] def __iter__(self): return iter(self.root) def __getitem__(self, item): return self.root[item] pets = Pets.model_validate(['dog', 'cat']) print(pets[0]) #> dog print([pet for pet in pets]) #> ['dog', 'cat'] ``` You can also create subclasses of the parametrized root model directly: ```python from pydantic import RootModel class Pets(RootModel[list[str]]): def describe(self) -> str: return f'Pets: {", ".join(self.root)}' my_pets = Pets.model_validate(['dog', 'cat']) print(my_pets.describe()) #> Pets: dog, cat ``` ## Faux immutability Models can be configured to be immutable via `model_config['frozen'] = True`. When this is set, attempting to change the values of instance attributes will raise errors. See the [API reference][pydantic.config.ConfigDict.frozen] for more details. !!! note This behavior was achieved in Pydantic V1 via the config setting `allow_mutation = False`. This config flag is deprecated in Pydantic V2, and has been replaced with `frozen`. !!! warning In Python, immutability is not enforced. Developers have the ability to modify objects that are conventionally considered "immutable" if they choose to do so. ```python from pydantic import BaseModel, ConfigDict, ValidationError class FooBarModel(BaseModel): model_config = ConfigDict(frozen=True) a: str b: dict foobar = FooBarModel(a='hello', b={'apple': 'pear'}) try: foobar.a = 'different' except ValidationError as e: print(e) """ 1 validation error for FooBarModel a Instance is frozen [type=frozen_instance, input_value='different', input_type=str] """ print(foobar.a) #> hello print(foobar.b) #> {'apple': 'pear'} foobar.b['apple'] = 'grape' print(foobar.b) #> {'apple': 'grape'} ``` Trying to change `a` caused an error, and `a` remains unchanged. However, the dict `b` is mutable, and the immutability of `foobar` doesn't stop `b` from being changed. ## Abstract base classes Pydantic models can be used alongside Python's [Abstract Base Classes](https://docs.python.org/3/library/abc.html) (ABCs). ```python import abc from pydantic import BaseModel class FooBarModel(BaseModel, abc.ABC): a: str b: int @abc.abstractmethod def my_abstract_method(self): pass ``` ## Field ordering Field order affects models in the following ways: * field order is preserved in the model [JSON Schema](json_schema.md) * field order is preserved in [validation errors](#error-handling) * field order is preserved when [serializing data](serialization.md#serializing-data) ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): a: int b: int = 2 c: int = 1 d: int = 0 e: float print(Model.model_fields.keys()) #> dict_keys(['a', 'b', 'c', 'd', 'e']) m = Model(e=2, a=1) print(m.model_dump()) #> {'a': 1, 'b': 2, 'c': 1, 'd': 0, 'e': 2.0} try: Model(a='x', b='x', c='x', d='x', e='x') except ValidationError as err: error_locations = [e['loc'] for e in err.errors()] print(error_locations) #> [('a',), ('b',), ('c',), ('d',), ('e',)] ``` ## Automatically excluded attributes ### Class variables Attributes annotated with [`ClassVar`][typing.ClassVar] are properly treated by Pydantic as class variables, and will not become fields on model instances: ```python from typing import ClassVar from pydantic import BaseModel class Model(BaseModel): x: ClassVar[int] = 1 y: int = 2 m = Model() print(m) #> y=2 print(Model.x) #> 1 ``` ### Private model attributes ??? api "API Documentation" [`pydantic.fields.PrivateAttr`][pydantic.fields.PrivateAttr]
Attributes whose name has a leading underscore are not treated as fields by Pydantic, and are not included in the model schema. Instead, these are converted into a "private attribute" which is not validated or even set during calls to `__init__`, `model_validate`, etc. Here is an example of usage: ```python from datetime import datetime from random import randint from typing import Any from pydantic import BaseModel, PrivateAttr class TimeAwareModel(BaseModel): _processed_at: datetime = PrivateAttr(default_factory=datetime.now) _secret_value: str def model_post_init(self, context: Any) -> None: # this could also be done with `default_factory`: self._secret_value = randint(1, 5) m = TimeAwareModel() print(m._processed_at) #> 2032-01-02 03:04:05.000006 print(m._secret_value) #> 3 ``` Private attribute names must start with underscore to prevent conflicts with model fields. However, dunder names (such as `__attr__`) are not supported, and will be completely ignored from the model definition. /// version-added | v2.13 Default factories can take the validated model data as an argument. /// ## Model signature All Pydantic models will have their signature generated based on their fields: ```python import inspect from pydantic import BaseModel, Field class FooModel(BaseModel): id: int name: str = None description: str = 'Foo' apple: int = Field(alias='pear') print(inspect.signature(FooModel)) #> (*, id: int, name: str = None, description: str = 'Foo', pear: int) -> None ``` An accurate signature is useful for introspection purposes and libraries like `FastAPI` or `hypothesis`. The generated signature will also respect custom `__init__` functions: ```python import inspect from pydantic import BaseModel class MyModel(BaseModel): id: int info: str = 'Foo' def __init__(self, id: int = 1, *, bar: str, **data) -> None: """My custom init!""" super().__init__(id=id, bar=bar, **data) print(inspect.signature(MyModel)) #> (id: int = 1, *, bar: str, info: str = 'Foo') -> None ``` To be included in the signature, a field's alias or name must be a valid Python identifier. Pydantic will prioritize a field's alias over its name when generating the signature, but may use the field name if the alias is not a valid Python identifier. If a field's alias and name are *both* not valid identifiers (which may be possible through exotic use of `create_model`), a `**data` argument will be added. In addition, the `**data` argument will always be present in the signature if `model_config['extra'] == 'allow'`. ## Structural pattern matching Pydantic supports structural pattern matching for models, as introduced by [PEP 636](https://peps.python.org/pep-0636/) in Python 3.10. ```python {requires="3.10" lint="skip"} from pydantic import BaseModel class Pet(BaseModel): name: str species: str a = Pet(name='Bones', species='dog') match a: # match `species` to 'dog', declare and initialize `dog_name` case Pet(species='dog', name=dog_name): print(f'{dog_name} is a dog') #> Bones is a dog # default case case _: print('No dog matched') ``` !!! note A match-case statement may seem as if it creates a new model, but don't be fooled; it is just syntactic sugar for getting an attribute and either comparing it or declaring and initializing it. ## Attribute copies In many cases, arguments passed to the constructor will be copied in order to perform validation and, where necessary, coercion. In this example, note that the ID of the list changes after the class is constructed because it has been copied during validation: ```python from pydantic import BaseModel class C1: arr = [] def __init__(self, in_arr): self.arr = in_arr class C2(BaseModel): arr: list[int] arr_orig = [1, 9, 10, 3] c1 = C1(arr_orig) c2 = C2(arr=arr_orig) print(f'{id(c1.arr) == id(c2.arr)=}') #> id(c1.arr) == id(c2.arr)=False ``` !!! note There are some situations where Pydantic does not copy attributes, such as when passing models — we use the model as is. You can override this behaviour by setting [`model_config['revalidate_instances'] = 'always'`](../api/config.md#pydantic.config.ConfigDict). pydantic-pydantic-ba0aa01/docs/concepts/performance.md000066400000000000000000000137331517143232300232060ustar00rootroot00000000000000# Performance tips In most cases Pydantic won't be your bottleneck, only follow this if you're sure it's necessary. ## In general, use `model_validate_json()` not `model_validate(json.loads(...))` On `model_validate(json.loads(...))`, the JSON is parsed in Python, then converted to a dict, then it's validated internally. On the other hand, `model_validate_json()` already performs the validation internally. There are a few cases where `model_validate(json.loads(...))` may be faster. Specifically, when using a `'before'` or `'wrap'` validator on a model, validation may be faster with the two step method. You can read more about these special cases in [this discussion](https://github.com/pydantic/pydantic/discussions/6388#discussioncomment-8193105). Many performance improvements are currently in the works for `pydantic-core`, see [this discussion](https://github.com/pydantic/pydantic/discussions/6388#discussioncomment-8194048). Once these changes are merged, we should be at the point where `model_validate_json()` is always faster than `model_validate(json.loads(...))`. ## `TypeAdapter` instantiated once The idea here is to avoid constructing validators and serializers more than necessary. Each time a `TypeAdapter` is instantiated, it will construct a new validator and serializer. If you're using a `TypeAdapter` in a function, it will be instantiated each time the function is called. Instead, instantiate it once, and reuse it. === ":x: Bad" ```python {lint="skip"} from pydantic import TypeAdapter def my_func(): adapter = TypeAdapter(list[int]) # do something with adapter ``` === ":white_check_mark: Good" ```python {lint="skip"} from pydantic import TypeAdapter adapter = TypeAdapter(list[int]) def my_func(): ... # do something with adapter ``` ## `Sequence` vs `list` or `tuple` with `Mapping` vs `dict` When using `Sequence`, Pydantic calls `isinstance(value, Sequence)` to check if the value is a sequence. Also, Pydantic will try to validate against different types of sequences, like `list` and `tuple`. If you know the value is a `list` or `tuple`, use `list` or `tuple` instead of `Sequence`. The same applies to `Mapping` and `dict`. If you know the value is a `dict`, use `dict` instead of `Mapping`. ## Don't do validation when you don't have to, use `Any` to keep the value unchanged If you don't need to validate a value, use `Any` to keep the value unchanged. ```python from typing import Any from pydantic import BaseModel class Model(BaseModel): a: Any model = Model(a=1) ``` ## Avoid extra information via subclasses of primitives === "Don't do this" ```python class CompletedStr(str): def __init__(self, s: str): self.s = s self.done = False ``` === "Do this" ```python from pydantic import BaseModel class CompletedModel(BaseModel): s: str done: bool = False ``` ## Use tagged union, not union Tagged union (or discriminated union) is a union with a field that indicates which type it is. ```python {test="skip"} from typing import Any, Literal from pydantic import BaseModel, Field class DivModel(BaseModel): el_type: Literal['div'] = 'div' class_name: str | None = None children: list[Any] | None = None class SpanModel(BaseModel): el_type: Literal['span'] = 'span' class_name: str | None = None contents: str | None = None class ButtonModel(BaseModel): el_type: Literal['button'] = 'button' class_name: str | None = None contents: str | None = None class InputModel(BaseModel): el_type: Literal['input'] = 'input' class_name: str | None = None value: str | None = None class Html(BaseModel): contents: DivModel | SpanModel | ButtonModel | InputModel = Field( discriminator='el_type' ) ``` See [Discriminated Unions] for more details. ## Use `TypedDict` over nested models Instead of using nested models, use `TypedDict` to define the structure of the data. ??? info "Performance comparison" With a simple benchmark, `TypedDict` is about ~2.5x faster than nested models: ```python {test="skip"} from timeit import timeit from typing_extensions import TypedDict from pydantic import BaseModel, TypeAdapter class A(TypedDict): a: str b: int class TypedModel(TypedDict): a: A class B(BaseModel): a: str b: int class Model(BaseModel): b: B ta = TypeAdapter(TypedModel) result1 = timeit( lambda: ta.validate_python({'a': {'a': 'a', 'b': 2}}), number=10000 ) result2 = timeit( lambda: Model.model_validate({'b': {'a': 'a', 'b': 2}}), number=10000 ) print(result2 / result1) ``` ## Avoid wrap validators if you really care about performance Wrap validators are generally slower than other validators. This is because they require that data is materialized in Python during validation. Wrap validators can be incredibly useful for complex validation logic, but if you're looking for the best performance, you should avoid them. ## Failing early with `FailFast` Starting in v2.8+, you can apply the `FailFast` annotation to sequence types to fail early if any item in the sequence fails validation. If you use this annotation, you won't get validation errors for the rest of the items in the sequence if one fails, so you're effectively trading off visibility for performance. ```python from typing import Annotated from pydantic import FailFast, TypeAdapter, ValidationError ta = TypeAdapter(Annotated[list[bool], FailFast()]) try: ta.validate_python([True, 'invalid', False, 'also invalid']) except ValidationError as exc: print(exc) """ 1 validation error for list[bool] 1 Input should be a valid boolean, unable to interpret input [type=bool_parsing, input_value='invalid', input_type=str] """ ``` Read more about `FailFast` [here][pydantic.types.FailFast]. [Discriminated Unions]: ../concepts/unions.md#discriminated-unions pydantic-pydantic-ba0aa01/docs/concepts/pydantic_settings.md000066400000000000000000000005351517143232300244340ustar00rootroot00000000000000--- description: Support for loading a settings or config class from environment variables or secrets files. --- # Settings Management [Pydantic Settings](https://github.com/pydantic/pydantic-settings) provides optional Pydantic features for loading a settings or config class from environment variables or secrets files. {{ pydantic_settings }} pydantic-pydantic-ba0aa01/docs/concepts/serialization.md000066400000000000000000000771011517143232300235610ustar00rootroot00000000000000Beyond accessing model attributes directly via their field names (e.g. `model.foobar`), models can be converted, dumped, serialized, and exported in a number of ways. Serialization can be customized for the whole model, or on a per-field or per-type basis. ??? abstract "Serialize versus dump" Pydantic uses the terms "serialize" and "dump" interchangeably. Both refer to the process of converting a model to a dictionary or JSON-encoded string. Outside of Pydantic, the word "serialize" usually refers to converting in-memory data into a string or bytes. However, in the context of Pydantic, there is a very close relationship between converting an object from a more structured form — such as a Pydantic model, a dataclass, etc. — into a less structured form comprised of Python built-ins such as dict. While we could (and on occasion, do) distinguish between these scenarios by using the word "dump" when converting to primitives and "serialize" when converting to string, for practical purposes, we frequently use the word "serialize" to refer to both of these situations, even though it does not always imply conversion to a string or bytes. !!! tip Want to quickly jump to the relevant serializer section?
* Field serializer --- * [field *plain* serializer](#field-plain-serializer) * [field *wrap* serializer](#field-wrap-serializer) * Model serializer --- * [model *plain* serializer](#model-plain-serializer) * [model *wrap* serializer](#model-wrap-serializer)
## Serializing data Pydantic allows models (and any other type using [type adapters](./type_adapter.md)) to be serialized in *two* modes: [Python](#python-mode) and [JSON](#json-mode). The Python output may contain non-JSON serializable data (although this can be emulated). [](){#modelmodel_dump} ### Python mode When using the Python mode, Pydantic models (and model-like types such as [dataclasses][]) (1) will be (recursively) converted to dictionaries. This is achievable by using the [`model_dump()`][pydantic.BaseModel.model_dump] method: { .annotate } 1. With the exception of [root models](./models.md#rootmodel-and-custom-root-types), where the root value is dumped directly. ```python {group="python-dump"} from typing import Optional from pydantic import BaseModel, Field class BarModel(BaseModel): whatever: tuple[int, ...] class FooBarModel(BaseModel): banana: Optional[float] = 1.1 foo: str = Field(serialization_alias='foo_alias') bar: BarModel m = FooBarModel(banana=3.14, foo='hello', bar={'whatever': (1, 2)}) # returns a dictionary: print(m.model_dump()) #> {'banana': 3.14, 'foo': 'hello', 'bar': {'whatever': (1, 2)}} print(m.model_dump(by_alias=True)) #> {'banana': 3.14, 'foo_alias': 'hello', 'bar': {'whatever': (1, 2)}} ``` Notice that the value of `whatever` was dumped as tuple, which isn't a known JSON type. The `mode` argument can be set to `'json'` to ensure JSON-compatible types are used: ```python {group="python-dump"} print(m.model_dump(mode='json')) #> {'banana': 3.14, 'foo': 'hello', 'bar': {'whatever': [1, 2]}} ``` !!! info "See also" The [`TypeAdapter.dump_python()`][pydantic.TypeAdapter.dump_python] method, useful when *not* dealing with Pydantic models. [](){#modelmodel_dump_json} ### JSON mode Pydantic allows data to be serialized directly to a JSON-encoded string, by trying its best to convert Python values to valid JSON data. This is achievable by using the [`model_dump_json()`][pydantic.BaseModel.model_dump_json] method: ```python from datetime import datetime from pydantic import BaseModel class BarModel(BaseModel): whatever: tuple[int, ...] class FooBarModel(BaseModel): foo: datetime bar: BarModel m = FooBarModel(foo=datetime(2032, 6, 1, 12, 13, 14), bar={'whatever': (1, 2)}) print(m.model_dump_json(indent=2)) """ { "foo": "2032-06-01T12:13:14", "bar": { "whatever": [ 1, 2 ] } } """ ``` In addition to the [supported types][json.JSONEncoder] by the standard library [`json`][] module, Pydantic supports a wide variety of types ([date and time types][datetime], [`UUID`][uuid.UUID] objects, [sets][set], etc). If an unsupported type is used and can't be serialized to JSON, a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] exception is raised. !!! info "See also" The [`TypeAdapter.dump_json()`][pydantic.TypeAdapter.dump_json] method, useful when *not* dealing with Pydantic models. [](){#dictmodel-and-iteration} ## Iterating over models Pydantic models can also be iterated over, yielding `(field_name, field_value)` pairs. Note that field values are left as is, so sub-models will *not* be converted to dictionaries: ```python {group="iterating-model"} from pydantic import BaseModel class BarModel(BaseModel): whatever: int class FooBarModel(BaseModel): banana: float foo: str bar: BarModel m = FooBarModel(banana=3.14, foo='hello', bar={'whatever': 123}) for name, value in m: print(f'{name}: {value}') #> banana: 3.14 #> foo: hello #> bar: whatever=123 ``` This means that calling [`dict()`][dict] on a model can be used to construct a dictionary of the model: ```python {group="iterating-model"} print(dict(m)) #> {'banana': 3.14, 'foo': 'hello', 'bar': BarModel(whatever=123)} ``` !!! note [Root models](models.md#rootmodel-and-custom-root-types) *does* get converted to a dictionary with the key `'root'`. [](){#pickledumpsmodel} ## Pickling support Pydantic models support efficient pickling and unpickling. ```python {test="skip"} import pickle from pydantic import BaseModel class FooBarModel(BaseModel): a: str b: int m = FooBarModel(a='hello', b=123) print(m) #> a='hello' b=123 data = pickle.dumps(m) print(data[:20]) #> b'\x80\x04\x95\x95\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main_' m2 = pickle.loads(data) print(m2) #> a='hello' b=123 ``` [](){#custom-serializers} ## Serializers Similar to [custom validators](./validators.md), you can leverage custom serializers at the field and model levels to further control the serialization behavior. !!! warning Only *one* serializer can be defined per field/model. It is not possible to combine multiple serializers together (including *plain* and *wrap* serializers). ### Field serializers ??? api "API Documentation" [`pydantic.functional_serializers.PlainSerializer`][pydantic.functional_serializers.PlainSerializer]
[`pydantic.functional_serializers.WrapSerializer`][pydantic.functional_serializers.WrapSerializer]
[`pydantic.functional_serializers.field_serializer`][pydantic.functional_serializers.field_serializer]
In its simplest form, a field serializer is a callable taking the value to be serialized as an argument and **returning the serialized value**. If the `return_type` argument is provided to the serializer (or if a return type annotation is available on the serializer function), it will be used to build an extra serializer, to ensure that the serialized field value complies with this return type. **Two** different types of serializers can be used. They can all be defined using the [annotated pattern](./fields.md#the-annotated-pattern) or using the [`@field_serializer`][pydantic.field_serializer] decorator, applied on instance or [static methods][staticmethod]. * ***Plain* serializers**: are called unconditionally to serialize a field. The serialization logic for types supported by Pydantic will *not* be called. Using such serializers is also useful to specify the logic for arbitrary types. {#field-plain-serializer} === "Annotated pattern" ```python from typing import Annotated, Any from pydantic import BaseModel, PlainSerializer def ser_number(value: Any) -> Any: if isinstance(value, int): return value * 2 else: return value class Model(BaseModel): number: Annotated[int, PlainSerializer(ser_number)] print(Model(number=4).model_dump()) #> {'number': 8} m = Model(number=1) m.number = 'invalid' print(m.model_dump()) # (1)! #> {'number': 'invalid'} ``` 1. Pydantic will *not* validate that the serialized value complies with the `int` type. === "Decorator" ```python from typing import Any from pydantic import BaseModel, field_serializer class Model(BaseModel): number: int @field_serializer('number', mode='plain') # (1)! def ser_number(self, value: Any) -> Any: if isinstance(value, int): return value * 2 else: return value print(Model(number=4).model_dump()) #> {'number': 8} m = Model(number=1) m.number = 'invalid' print(m.model_dump()) # (2)! #> {'number': 'invalid'} ``` 1. `'plain'` is the default mode for the decorator, and can be omitted. 2. Pydantic will *not* validate that the serialized value complies with the `int` type. * ***Wrap* serializers**: give more flexibility to customize the serialization behavior. You can run code before or after the Pydantic serialization logic. {#field-wrap-serializer} Such serializers must be defined with a **mandatory** extra *handler* parameter: a callable taking the value to be serialized as an argument. Internally, this handler will delegate serialization of the value to Pydantic. You are free to *not* call the handler at all. === "Annotated pattern" ```python from typing import Annotated, Any from pydantic import BaseModel, SerializerFunctionWrapHandler, WrapSerializer def ser_number(value: Any, handler: SerializerFunctionWrapHandler) -> int: return handler(value) + 1 class Model(BaseModel): number: Annotated[int, WrapSerializer(ser_number)] print(Model(number=4).model_dump()) #> {'number': 5} ``` === "Decorator" ```python from typing import Any from pydantic import BaseModel, SerializerFunctionWrapHandler, field_serializer class Model(BaseModel): number: int @field_serializer('number', mode='wrap') def ser_number( self, value: Any, handler: SerializerFunctionWrapHandler ) -> int: return handler(value) + 1 print(Model(number=4).model_dump()) #> {'number': 5} ``` #### Which serializer pattern to use While both approaches can achieve the same thing, each pattern provides different benefits. ##### Using the annotated pattern One of the key benefits of using the [annotated pattern](./fields.md#the-annotated-pattern) is to make serializers reusable: ```python from typing import Annotated from pydantic import BaseModel, Field, PlainSerializer DoubleNumber = Annotated[int, PlainSerializer(lambda v: v * 2)] class Model1(BaseModel): my_number: DoubleNumber class Model2(BaseModel): other_number: Annotated[DoubleNumber, Field(description='My other number')] class Model3(BaseModel): list_of_even_numbers: list[DoubleNumber] # (1)! ``` 1. As mentioned in the [annotated pattern](./fields.md#the-annotated-pattern) documentation, we can also make use of serializers for specific parts of the annotation (in this case, serialization is applied for list items, but not the whole list). It is also easier to understand which serializers are applied to a type, by just looking at the field annotation. ##### Using the decorator pattern One of the key benefits of using the [`@field_serializer`][pydantic.field_serializer] decorator is to apply the function to multiple fields: ```python from pydantic import BaseModel, field_serializer class Model(BaseModel): f1: str f2: str @field_serializer('f1', 'f2', mode='plain') def capitalize(self, value: str) -> str: return value.capitalize() ``` Here are a couple additional notes about the decorator usage: * If you want the serializer to apply to all fields (including the ones defined in subclasses), you can pass `'*'` as the field name argument. * By default, the decorator will ensure the provided field name(s) are defined on the model. If you want to disable this check during class creation, you can do so by passing `False` to the `check_fields` argument. This is useful when the field serializer is defined on a base class, and the field is expected to exist on subclasses. ### Model serializers ??? api "API Documentation" [`pydantic.functional_serializers.model_serializer`][pydantic.functional_serializers.model_serializer]
Serialization can also be customized on the entire model using the [`@model_serializer`][pydantic.model_serializer] decorator. If the `return_type` argument is provided to the [`@model_serializer`][pydantic.model_serializer] decorator (or if a return type annotation is available on the serializer function), it will be used to build an extra serializer, to ensure that the serialized model value complies with this return type. As with [field serializers](#field-serializers), **two** different types of model serializers can be used: * ***Plain* serializers**: are called unconditionally to serialize the model. {#model-plain-serializer} ```python from pydantic import BaseModel, model_serializer class UserModel(BaseModel): username: str password: str @model_serializer(mode='plain') # (1)! def serialize_model(self) -> str: # (2)! return f'{self.username} - {self.password}' print(UserModel(username='foo', password='bar').model_dump()) #> foo - bar ``` 1. `'plain'` is the default mode for the decorator, and can be omitted. 2. You are free to return a value that *isn't* a dictionary. * ***Wrap* serializers**: give more flexibility to customize the serialization behavior. You can run code before or after the Pydantic serialization logic. {#model-wrap-serializer} Such serializers must be defined with a **mandatory** extra *handler* parameter: a callable taking the instance of the model as an argument. Internally, this handler will delegate serialization of the model to Pydantic. You are free to *not* call the handler at all. ```python from pydantic import BaseModel, SerializerFunctionWrapHandler, model_serializer class UserModel(BaseModel): username: str password: str @model_serializer(mode='wrap') def serialize_model( self, handler: SerializerFunctionWrapHandler ) -> dict[str, object]: serialized = handler(self) serialized['fields'] = list(serialized) return serialized print(UserModel(username='foo', password='bar').model_dump()) #> {'username': 'foo', 'password': 'bar', 'fields': ['username', 'password']} ``` ## Serialization info Both the field and model serializers callables (in all modes) can optionally take an extra `info` argument, providing useful extra information, such as: * [user defined context](#serialization-context) * the current serialization mode: either `'python'` or `'json'` (see the [`mode`][pydantic.SerializationInfo.mode] property) * the various parameters set during serialization using the [serialization methods](#serializing-data) (e.g. [`exclude_unset`][pydantic.SerializationInfo.exclude_unset], [`serialize_as_any`][pydantic.SerializationInfo.serialize_as_any]) * the current field name, if using a [field serializer](#field-serializers) (see the [`field_name`][pydantic.FieldSerializationInfo.field_name] property). ### Serialization context You can pass a context object to the [serialization methods](#serializing-data), which can be accessed inside the serializer functions using the [`context`][pydantic.SerializationInfo.context] property: ```python from pydantic import BaseModel, FieldSerializationInfo, field_serializer class Model(BaseModel): text: str @field_serializer('text', mode='plain') @classmethod def remove_stopwords(cls, v: str, info: FieldSerializationInfo) -> str: if isinstance(info.context, dict): stopwords = info.context.get('stopwords', set()) v = ' '.join(w for w in v.split() if w.lower() not in stopwords) return v model = Model(text='This is an example document') print(model.model_dump()) # no context #> {'text': 'This is an example document'} print(model.model_dump(context={'stopwords': ['this', 'is', 'an']})) #> {'text': 'example document'} ``` Similarly, you can [use a context for validation](../concepts/validators.md#validation-context). ## Serializing subclasses [](){#subclasses-of-standard-types} ### Subclasses of supported types Subclasses of supported types are serialized according to their super class: ```python from datetime import date from pydantic import BaseModel class MyDate(date): @property def my_date_format(self) -> str: return self.strftime('%d/%m/%Y') class FooModel(BaseModel): date: date m = FooModel(date=MyDate(2023, 1, 1)) print(m.model_dump_json()) #> {"date":"2023-01-01"} ``` [](){#subclass-instances-for-fields-of-basemodel-dataclasses-typeddict} ### Subclasses of model-like types When using model-like classes (Pydantic models, [dataclasses](./dataclasses.md), etc.) as field annotations, the default behavior is to serialize the field value as though it was an instance of the class used as the annotation, even if it is a subclass. More specifically, only the fields declared on the type annotation will be included in the serialization result: ```python from pydantic import BaseModel class User(BaseModel): name: str class UserLogin(User): password: str class OuterModel(BaseModel): user: User user = UserLogin(name='pydantic', password='hunter2') m = OuterModel(user=user) print(m) #> user=UserLogin(name='pydantic', password='hunter2') print(m.model_dump()) # (1)! #> {'user': {'name': 'pydantic'}} ``` 1. Note: the password field is not included !!! warning "Migration Warning" This behavior is different from how things worked in Pydantic V1, where we would always include all (subclass) fields when recursively serializing models to dictionaries. The motivation behind this change in behavior is that it helps ensure that you know precisely which fields could be included when serializing, even if subclasses get passed when instantiating the object. In particular, this can help prevent surprises when adding sensitive information like secrets as fields of subclasses. To enable the old V1 behavior, refer to the next section. [](){#serializing-with-duck-typing} ### Polymorphic serialization /// version-added | v2.13 Polymorphic serialization was added as an better alternative to the [serialize as any](#serializing-as-any) behavior, and only applies to Pydantic models and Pydantic dataclasses. /// Polymorphic serialization is the behavior of serializing a model (or [Pydantic dataclass](./dataclasses.md)) instance according to the serialization schema of such instance, rather that the schema of the class used as the type. This will expose all the data defined on the subclass in the serialized payload. This behavior can be configured in the following ways: * Configuration level: use the [`polymorphic_serialization`][pydantic.config.ConfigDict.polymorphic_serialization] setting in the model/dataclass [configuration](./config.md). * Runtime level: use the `polymorphic_serialization` argument when calling the [serialization methods](#serializing-data). This will apply to all (nested) types, overriding any configuration. !!! note "Duck-typed serialization" This behavior (and the ["any" serialization](#serializing-as-any) discussed below) was previously referred to as duck-typed serialization. This was a misnomer; it did not function like [duck typing](https://en.wikipedia.org/wiki/Duck_typing) in the conventional programming language sense. !!! warning Polymorphic serialization of standard library dataclasses Polymorphic serialization is only supported for Pydantic models and [Pydantic dataclasses](./dataclasses.md). When using [standard library dataclasses][dataclasses], polymorphic serialization is *not* supported, even if the dataclass is a subclass of a Pydantic dataclass. This may be fixed in a future Pydantic release. The example below defines a type `User` and a subclass of it, `UserLogin`. A second pair of types, `PolymorphicUser` and `PolymorphicUserLogin` are defined as equivalents with `polymorphic_serialization` enabled. We can then see the effect of serializing each of these types, and the interaction of this config with the runtime `polymorphic_serialization` setting: ```python from pydantic import BaseModel class User(BaseModel): name: str class UserLogin(User): password: str class OuterModel(BaseModel): user: User outer_model = OuterModel( user=UserLogin(name='pydantic', password='password'), ) print(outer_model.model_dump()) # (1)! #> {'user': {'name': 'pydantic'}} print(outer_model.model_dump(polymorphic_serialization=True)) # (2)! #> {'user': {'name': 'pydantic', 'password': 'password'}} ``` 1. With polymorphic serialization disabled, `user` serializes as the base type. 2. With polymorphic serialization enabled, `user` serializes as the actual runtime subclass. As seen in the example, by having polymorphic serialization enabled, the `User.model_dump()` method will by respect the value of the `UserLogin` subclass when it is provided instead of a `User` value, and serialize the full `UserLogin` type. This behavior can be globally overridden with the `polymorphic_serialization` runtime setting; in this case setting it to `False` causes the `UserLogin` value to serialize just as a `User` value, ignoring the subclass' `password` field. ## Serializing "as Any" A more extreme form of [polymorphic serialization](#polymorphic-serialization) is "any" serialization. In this mode, Pydantic does *not* make use of any type annotation (more precisely, the serialization schema derived from the type) to infer how the value should be serialized, but instead inspects the actual type of the value at runtime to do so (and this applies to *all* types, not only Pydantic models and dataclasses). This means that every value will be serialized exactly based on its runtime type and any knowledge Pydantic has of how to serialize the type. Pydantic can infer how to serialize the following types: * Many Python standard library types (exact set may be expanded depending on Pydantic version). * Types with a `__pydantic_serializer__` attribute. * Any type serializable with the `fallback` function passed as an argument to [serialization methods](#serializing-data). In most cases, you will want to use the [polymorphic serialization](#polymorphic-serialization) behavior instead. This behavior can be configured at the field level and at runtime, for a specific serialization call: * Field level: use the [`SerializeAsAny`][pydantic.functional_serializers.SerializeAsAny] annotation. * Runtime level: use the `serialize_as_any` argument when calling the [serialization methods](#serializing-data). These options are discussed below in more detail. ### `SerializeAsAny` annotation If you want duck typing serialization behavior, this can be done using the [`SerializeAsAny`][pydantic.functional_serializers.SerializeAsAny] annotation on a type: ```python from pydantic import BaseModel, SerializeAsAny class User(BaseModel): name: str class UserLogin(User): password: str class OuterModel(BaseModel): as_any: SerializeAsAny[User] as_user: User user = UserLogin(name='pydantic', password='password') print(OuterModel(as_any=user, as_user=user).model_dump()) """ { 'as_any': {'name': 'pydantic', 'password': 'password'}, 'as_user': {'name': 'pydantic'}, } """ ``` When a type is annotated as `SerializeAsAny[]`, the validation behavior will be the same as if it was annotated as ``, and static type checkers will treat the annotation as if it was simply ``. When serializing, the field will be serialized as though the type hint for the field was [`Any`][typing.Any], which is where the name comes from. ### `serialize_as_any` runtime setting The `serialize_as_any` runtime setting can be used to serialize model data with or without duck typed serialization behavior. `serialize_as_any` can be passed as a keyword argument to the various [serialization methods](#serializing-data) (such as [`model_dump()`][pydantic.BaseModel.model_dump] and [`model_dump_json()`][pydantic.BaseModel.model_dump_json] on Pydantic models). ```python from pydantic import BaseModel class User(BaseModel): name: str class UserLogin(User): password: str class OuterModel(BaseModel): user1: User user2: User user = UserLogin(name='pydantic', password='password') outer_model = OuterModel(user1=user, user2=user) print(outer_model.model_dump(serialize_as_any=True)) # (1)! """ { 'user1': {'name': 'pydantic', 'password': 'password'}, 'user2': {'name': 'pydantic', 'password': 'password'}, } """ print(outer_model.model_dump(serialize_as_any=False)) # (2)! #> {'user1': {'name': 'pydantic'}, 'user2': {'name': 'pydantic'}} ``` 1. With `serialize_as_any` set to `True`, the result matches that of V1. 2. With `serialize_as_any` set to `False` (the V2 default), fields present on the subclass, but not the base class, are not included in serialization. However, do note that the *serialize as any* behavior will apply to *all* values, not only the values where duck typing is relevant. You may want to prefer using the `SerializeAsAny` annotation when required instead. [](){#advanced-include-and-exclude} [](){#model-and-field-level-include-and-exclude} ## Field inclusion and exclusion For serialization, field inclusion and exclusion can be configured in two ways: * at the field level, using the `exclude` and `exclude_if` parameters on [the `Field()` function](fields.md). * using the various serialization parameters on the [serialization methods](#serializing-data). ### At the field level At the field level, the `exclude` and `exclude_if` parameters can be used: ```python from pydantic import BaseModel, Field class Transaction(BaseModel): id: int private_id: int = Field(exclude=True) value: int = Field(ge=0, exclude_if=lambda v: v == 0) print(Transaction(id=1, private_id=2, value=0).model_dump()) #> {'id': 1} ``` Exclusion at the field level takes priority over the `include` serialization parameter described below. ### As parameters to the serialization methods When using the [serialization methods](#serializing-data) (such as [`model_dump()`][pydantic.BaseModel.model_dump]), several parameters can be used to exclude or include fields. #### Excluding and including specific fields Consider the following models: ```python {group="simple-exclude-include"} from pydantic import BaseModel, Field, SecretStr class User(BaseModel): id: int username: str password: SecretStr class Transaction(BaseModel): id: str private_id: str = Field(exclude=True) user: User value: int t = Transaction( id='1234567890', private_id='123', user=User(id=42, username='JohnDoe', password='hashedpassword'), value=9876543210, ) ``` The `exclude` parameter can be used to specify which fields should be excluded (including the others), and vice-versa using the `include` parameter. ```python {group="simple-exclude-include"} # using a set: print(t.model_dump(exclude={'user', 'value'})) #> {'id': '1234567890'} # using a dictionary: print(t.model_dump(exclude={'user': {'username', 'password'}, 'value': True})) #> {'id': '1234567890', 'user': {'id': 42}} # same configuration using `include`: print(t.model_dump(include={'id': True, 'user': {'id'}})) #> {'id': '1234567890', 'user': {'id': 42}} ``` Note that using `False` to *include* a field in `exclude` (or to *exclude* a field in `include`) is not supported. It is also possible to exclude or include specific items from sequence and dictionaries: ```python {group="advanced-include-exclude"} from pydantic import BaseModel class Hobby(BaseModel): name: str info: str class User(BaseModel): hobbies: list[Hobby] user = User( hobbies=[ Hobby(name='Programming', info='Writing code and stuff'), Hobby(name='Gaming', info='Hell Yeah!!!'), ], ) print(user.model_dump(exclude={'hobbies': {-1: {'info'}}})) # (1)! """ { 'hobbies': [ {'name': 'Programming', 'info': 'Writing code and stuff'}, {'name': 'Gaming'}, ] } """ ``` 1. The equivalent call with `include` would be: ```python {lint="skip" group="advanced-include-exclude"} user.model_dump( include={'hobbies': {0: True, -1: {'name'}}} ) ``` The special key `'__all__'` can be used to apply an exclusion/inclusion pattern to all members: ```python {group="advanced-include-exclude"} print(user.model_dump(exclude={'hobbies': {'__all__': {'info'}}})) #> {'hobbies': [{'name': 'Programming'}, {'name': 'Gaming'}]} ``` #### Excluding and including fields based on their value When using the [serialization methods](#serializing-data), it is possible to exclude fields based on their value, using the following parameters: * `exclude_defaults`: Exclude all fields whose value compares equal to the default value (using the equality (`==`) comparison operator). * `exclude_none`: Exclude all fields whose value is `None`. * `exclude_unset`: Pydantic keeps track of fields that were *explicitly* set during instantiation (using the [`model_fields_set`][pydantic.BaseModel.model_fields_set] property). Using `exclude_unset`, any field that was not explicitly provided will be excluded: ```python {group="exclude-unset"} from pydantic import BaseModel class UserModel(BaseModel): name: str age: int = 18 user = UserModel(name='John') print(user.model_fields_set) #> {'name'} print(user.model_dump(exclude_unset=True)) #> {'name': 'John'} ``` Note that altering a field *after* the instance has been created will remove it from the unset fields: ```python {group="exclude-unset"} user.age = 21 print(user.model_dump(exclude_unset=True)) #> {'name': 'John', 'age': 21} ``` !!! tip The experimental [`MISSING` sentinel](./experimental.md#missing-sentinel) can be used as an alternative to `exclude_unset`. Any field with `MISSING` as a value is automatically excluded from the serialization output. pydantic-pydantic-ba0aa01/docs/concepts/strict_mode.md000066400000000000000000000134231517143232300232150ustar00rootroot00000000000000??? api "API Documentation" [`pydantic.types.Strict`][pydantic.types.Strict]
By default, Pydantic will attempt to coerce values to the desired type when possible. For example, you can pass the string `'123'` as the input for the [`int` number type](../api/standard_library_types.md#integers), and it will be converted to the value `123`. This coercion behavior is useful in many scenarios — think: UUIDs, URL parameters, HTTP headers, environment variables, dates, etc. However, there are also situations where this is not desirable, and you want Pydantic to error instead of coercing data. To better support this use case, Pydantic provides a "strict mode". When strict mode is enabled, Pydantic will be much less lenient when coercing data, and will instead error if the data is not of the correct type. Most of the time, strict mode will only allow instances of the type to be provided, although looser rules may apply to JSON input (for instance, the [date and time types](../api/standard_library_types.md#date-and-time-types) allow strings even in strict mode). The strict behavior for each type can be found in the [standard library types](../api/standard_library_types.md) documentation, and is summarized in the [conversion table](./conversion_table.md). Here is a brief example showing the validation behavior difference in strict and the default lax mode: ```python from pydantic import BaseModel, ValidationError class MyModel(BaseModel): x: int print(MyModel.model_validate({'x': '123'})) # lax mode #> x=123 try: MyModel.model_validate({'x': '123'}, strict=True) # strict mode except ValidationError as exc: print(exc) """ 1 validation error for MyModel x Input should be a valid integer [type=int_type, input_value='123', input_type=str] """ ``` Strict mode can be enabled in various ways: * [As a validation parameter](#as-a-validation-parameter), such as when using [`model_validate()`][pydantic.BaseModel.model_validate], on Pydantic models. * [At the field level](#at-the-field-level). * [At the configuration level](#as-a-configuration-value) (with the possibility to override at the field level). [](){#strict-mode-in-method-calls} ## As a validation parameter Strict mode can be enaled on a per-validation-call basis, when using the [validation methods](./models.md#validating-data) on [Pydantic models](./models.md) and [type adapters](./type_adapter.md). ```python from datetime import date from pydantic import TypeAdapter, ValidationError print(TypeAdapter(date).validate_python('2000-01-01')) # OK: lax #> 2000-01-01 try: # Not OK: strict: TypeAdapter(date).validate_python('2000-01-01', strict=True) except ValidationError as exc: print(exc) """ 1 validation error for date Input should be a valid date [type=date_type, input_value='2000-01-01', input_type=str] """ TypeAdapter(date).validate_json('"2000-01-01"', strict=True) # (1)! #> 2000-01-01 ``` 1. As mentioned, strict mode is looser when validating from JSON. [](){#strict-mode-with-field} ## At the field level Strict mode can be enabled on specific fields, by setting the `strict` parameter of the [`Field()`][pydantic.Field] function to `True`. Strict mode will be applied for such fields, even when the [validation methods](./models.md#validating-data) are called in lax mode. ```python from pydantic import BaseModel, Field, ValidationError class User(BaseModel): name: str age: int = Field(strict=True) # (1)! user = User(name='John', age=42) print(user) #> name='John' age=42 try: another_user = User(name='John', age='42') except ValidationError as e: print(e) """ 1 validation error for User age Input should be a valid integer [type=int_type, input_value='42', input_type=str] """ ``` 1. The strict constraint can also be applied using the [annotated pattern](./fields.md#the-annotated-pattern): `Annotated[int, Field(strict=True)]` [](){#strict-mode-with-annotated-strict} ### Using the `Strict()` metadata class ??? api "API Documentation" [`pydantic.types.Strict`][pydantic.types.Strict]
As an alternative to the [`Field()`][pydantic.Field] function, Pydantic provides the [`Strict`][pydantic.types.Strict] metadata class, meant to be used with the [annotated pattern](./fields.md#the-annotated-pattern). It also provides convenience aliases for the most common types (namely [`StrictBool`][pydantic.types.StrictBool], [`StrictInt`][pydantic.types.StrictInt], [`StrictFloat`][pydantic.types.StrictFloat], [`StrictStr`][pydantic.types.StrictStr] and [`StrictBytes`][pydantic.types.StrictBytes]). ```python from typing import Annotated from uuid import UUID from pydantic import BaseModel, Strict, StrictInt class User(BaseModel): id: Annotated[UUID, Strict()] age: StrictInt # (1)! ``` 1. Equivalent to `Annotated[int, Strict()]`. [](){#strict-mode-with-configdict} ## As a configuration value Strict mode behavior can be controlled at the [configuration](./config.md) level. When used on a Pydantic model (or model like class such as [dataclasses](./dataclasses.md)), strictness can still be overridden at the [field level](#at-the-field-level): ```python from pydantic import BaseModel, ConfigDict, Field class User(BaseModel): model_config = ConfigDict(strict=True) name: str age: int = Field(strict=False) print(User(name='John', age='18')) #> name='John' age=18 ``` pydantic-pydantic-ba0aa01/docs/concepts/type_adapter.md000066400000000000000000000120031517143232300233530ustar00rootroot00000000000000You may have types that are not `BaseModel`s that you want to validate data against. Or you may want to validate a `list[SomeModel]`, or dump it to JSON. ??? api "API Documentation" [`pydantic.type_adapter.TypeAdapter`][pydantic.type_adapter.TypeAdapter]
For use cases like this, Pydantic provides [`TypeAdapter`][pydantic.type_adapter.TypeAdapter], which can be used for type validation, serialization, and JSON schema generation without needing to create a [`BaseModel`][pydantic.main.BaseModel]. A [`TypeAdapter`][pydantic.type_adapter.TypeAdapter] instance exposes some of the functionality from [`BaseModel`][pydantic.main.BaseModel] instance methods for types that do not have such methods (such as dataclasses, primitive types, and more): ```python from typing_extensions import TypedDict from pydantic import TypeAdapter, ValidationError class User(TypedDict): name: str id: int user_list_adapter = TypeAdapter(list[User]) user_list = user_list_adapter.validate_python([{'name': 'Fred', 'id': '3'}]) print(repr(user_list)) #> [{'name': 'Fred', 'id': 3}] try: user_list_adapter.validate_python( [{'name': 'Fred', 'id': 'wrong', 'other': 'no'}] ) except ValidationError as e: print(e) """ 1 validation error for list[User] 0.id Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='wrong', input_type=str] """ print(repr(user_list_adapter.dump_json(user_list))) #> b'[{"name":"Fred","id":3}]' ``` !!! info "`dump_json` returns `bytes`" `TypeAdapter`'s `dump_json` methods returns a `bytes` object, unlike the corresponding method for `BaseModel`, `model_dump_json`, which returns a `str`. The reason for this discrepancy is that in V1, model dumping returned a str type, so this behavior is retained in V2 for backwards compatibility. For the `BaseModel` case, `bytes` are coerced to `str` types, but `bytes` are often the desired end type. Hence, for the new `TypeAdapter` class in V2, the return type is simply `bytes`, which can easily be coerced to a `str` type if desired. !!! note Despite some overlap in use cases with [`RootModel`][pydantic.root_model.RootModel], [`TypeAdapter`][pydantic.type_adapter.TypeAdapter] should not be used as a type annotation for specifying fields of a `BaseModel`, etc. ## Parsing data into a specified type [`TypeAdapter`][pydantic.type_adapter.TypeAdapter] can be used to apply the parsing logic to populate Pydantic models in a more ad-hoc way. This function behaves similarly to [`BaseModel.model_validate`][pydantic.main.BaseModel.model_validate], but works with arbitrary Pydantic-compatible types. This is especially useful when you want to parse results into a type that is not a direct subclass of [`BaseModel`][pydantic.main.BaseModel]. For example: ```python from pydantic import BaseModel, TypeAdapter class Item(BaseModel): id: int name: str # `item_data` could come from an API call, eg., via something like: # item_data = requests.get('https://my-api.com/items').json() item_data = [{'id': 1, 'name': 'My Item'}] items = TypeAdapter(list[Item]).validate_python(item_data) print(items) #> [Item(id=1, name='My Item')] ``` [`TypeAdapter`][pydantic.type_adapter.TypeAdapter] is capable of parsing data into any of the types Pydantic can handle as fields of a [`BaseModel`][pydantic.main.BaseModel]. !!! info "Performance considerations" When creating an instance of [`TypeAdapter`][pydantic.type_adapter.TypeAdapter], the provided type must be analyzed and converted into a pydantic-core schema. This comes with some non-trivial overhead, so it is recommended to create a `TypeAdapter` for a given type just once and reuse it in loops or other performance-critical code. ## Rebuilding a `TypeAdapter`'s schema /// version-added | v2.10 /// [`TypeAdapter`][pydantic.type_adapter.TypeAdapter]'s support deferred schema building and manual rebuilds. This is helpful for the case of: * Types with forward references * Types for which core schema builds are expensive When you initialize a [`TypeAdapter`][pydantic.type_adapter.TypeAdapter] with a type, Pydantic analyzes the type and creates a core schema for it. This core schema contains the information needed to validate and serialize data for that type. See the [architecture documentation](../internals/architecture.md) for more information on core schemas. If you set [`defer_build`][pydantic.config.ConfigDict.defer_build] to `True` when initializing a `TypeAdapter`, Pydantic will defer building the core schema until the first time it is needed (for validation or serialization). In order to manually trigger the building of the core schema, you can call the [`rebuild`][pydantic.type_adapter.TypeAdapter.rebuild] method on the [`TypeAdapter`][pydantic.type_adapter.TypeAdapter] instance: ```python from pydantic import ConfigDict, TypeAdapter ta = TypeAdapter('MyInt', config=ConfigDict(defer_build=True)) # some time later, the forward reference is defined MyInt = int ta.rebuild() assert ta.validate_python(1) == 1 ``` pydantic-pydantic-ba0aa01/docs/concepts/types.md000066400000000000000000000741071517143232300220530ustar00rootroot00000000000000Pydantic uses types to define how validation and serialization should be performed. [Built-in and standard library types](../api/standard_library_types.md) (such as [`int`][], [`str`][], [`date`][datetime.date]) can be used as is. [Strictness](./strict_mode.md) can be controlled and constraints can be applied on them. On top of these, Pydantic provides extra types, either [directly in the library](../api/types.md) (e.g. [`SecretStr`][pydantic.types.SecretStr]) or in the [`pydantic-extra-types`](https://github.com/pydantic/pydantic-extra-types) external library. These are implemented using the patterns described in the [custom types](#custom-types) section. Strictness and constraints *can't* be applied on them. The [built-in and standard library types](../api/standard_library_types.md) documentation goes over the supported types: the allowed values, the possible validation constraints, and whether [strictness](./strict_mode.md) can be configured. See also the [conversion table](../concepts/conversion_table.md) for a summary of the allowed values for each type. This page will go over defining your own custom types. ## Custom Types There are several ways to define your custom types. ### Using the annotated pattern The [annotated pattern](./fields.md#the-annotated-pattern) can be used to make types reusable across your code base. For example, to create a type representing a positive integer: ```python from typing import Annotated from pydantic import Field, TypeAdapter, ValidationError PositiveInt = Annotated[int, Field(gt=0)] # (1)! ta = TypeAdapter(PositiveInt) print(ta.validate_python(1)) #> 1 try: ta.validate_python(-1) except ValidationError as exc: print(exc) """ 1 validation error for constrained-int Input should be greater than 0 [type=greater_than, input_value=-1, input_type=int] """ ``` 1. Note that you can also use constraints from the [annotated-types](https://github.com/annotated-types/annotated-types) library to make this Pydantic-agnostic: ```python {test="skip" lint="skip"} from annotated_types import Gt PositiveInt = Annotated[int, Gt(0)] ``` #### Adding validation and serialization You can add or override validation, serialization, and JSON schemas to an arbitrary type using the markers that Pydantic exports: ```python from typing import Annotated from pydantic import ( AfterValidator, PlainSerializer, TypeAdapter, WithJsonSchema, ) TruncatedFloat = Annotated[ float, AfterValidator(lambda x: round(x, 1)), PlainSerializer(lambda x: f'{x:.1e}', return_type=str), WithJsonSchema({'type': 'string'}, mode='serialization'), ] ta = TypeAdapter(TruncatedFloat) input = 1.02345 assert input != 1.0 assert ta.validate_python(input) == 1.0 assert ta.dump_json(input) == b'"1.0e+00"' assert ta.json_schema(mode='validation') == {'type': 'number'} assert ta.json_schema(mode='serialization') == {'type': 'string'} ``` #### Generics [Type variables][typing.TypeVar] can be used within the [`Annotated`][typing.Annotated] type: ```python from typing import Annotated, TypeVar from annotated_types import Gt, Len from pydantic import TypeAdapter, ValidationError T = TypeVar('T') ShortList = Annotated[list[T], Len(max_length=4)] ta = TypeAdapter(ShortList[int]) v = ta.validate_python([1, 2, 3, 4]) assert v == [1, 2, 3, 4] try: ta.validate_python([1, 2, 3, 4, 5]) except ValidationError as exc: print(exc) """ 1 validation error for list[int] List should have at most 4 items after validation, not 5 [type=too_long, input_value=[1, 2, 3, 4, 5], input_type=list] """ PositiveList = list[Annotated[T, Gt(0)]] ta = TypeAdapter(PositiveList[float]) v = ta.validate_python([1.0]) assert type(v[0]) is float try: ta.validate_python([-1.0]) except ValidationError as exc: print(exc) """ 1 validation error for list[constrained-float] 0 Input should be greater than 0 [type=greater_than, input_value=-1.0, input_type=float] """ ``` ### Named type aliases /// version-added | v2.11 Named type aliases are now fully supported. /// The above examples make use of *implicit* type aliases, assigned to a variable. At runtime, Pydantic has no way of knowing the name of the variable it was assigned to, and this can be problematic for two reasons: * The [JSON Schema](./json_schema.md) of the alias won't be converted into a [definition](https://json-schema.org/understanding-json-schema/structuring#defs). This is mostly useful when you are using the alias more than once in a model definition. * In most cases, [recursive type aliases](#named-recursive-types) won't work. By leveraging the new [`type` statement](https://typing.readthedocs.io/en/latest/spec/aliases.html#type-statement) (introduced in [PEP 695](https://peps.python.org/pep-0695/)), you can define aliases as follows: === "Python 3.9 and above" ```python from typing import Annotated from annotated_types import Gt from typing_extensions import TypeAliasType from pydantic import BaseModel PositiveIntList = TypeAliasType('PositiveIntList', list[Annotated[int, Gt(0)]]) class Model(BaseModel): x: PositiveIntList y: PositiveIntList print(Model.model_json_schema()) # (1)! """ { '$defs': { 'PositiveIntList': { 'items': {'exclusiveMinimum': 0, 'type': 'integer'}, 'type': 'array', } }, 'properties': { 'x': {'$ref': '#/$defs/PositiveIntList'}, 'y': {'$ref': '#/$defs/PositiveIntList'}, }, 'required': ['x', 'y'], 'title': 'Model', 'type': 'object', } """ ``` 1. If `PositiveIntList` were to be defined as an implicit type alias, its definition would have been duplicated in both `'x'` and `'y'`. === "Python 3.12 and above (new syntax)" ```python {requires="3.12" upgrade="skip" lint="skip"} from typing import Annotated from annotated_types import Gt from pydantic import BaseModel type PositiveIntList = list[Annotated[int, Gt(0)]] class Model(BaseModel): x: PositiveIntList y: PositiveIntList print(Model.model_json_schema()) # (1)! """ { '$defs': { 'PositiveIntList': { 'items': {'exclusiveMinimum': 0, 'type': 'integer'}, 'type': 'array', } }, 'properties': { 'x': {'$ref': '#/$defs/PositiveIntList'}, 'y': {'$ref': '#/$defs/PositiveIntList'}, }, 'required': ['x', 'y'], 'title': 'Model', 'type': 'object', } """ ``` 1. If `PositiveIntList` were to be defined as an implicit type alias, its definition would have been duplicated in both `'x'` and `'y'`. [](){#metadata-type-alias-warning} !!! warning "When to use named type aliases" While (named) PEP 695 and implicit type aliases are meant to be equivalent for static type checkers, Pydantic will *not* understand field-specific metadata inside named aliases. That is, metadata such as `alias`, `default`, `deprecated`, *cannot* be used: === "Python 3.9 and above" ```python {test="skip"} from typing import Annotated from typing_extensions import TypeAliasType from pydantic import BaseModel, Field MyAlias = TypeAliasType('MyAlias', Annotated[int, Field(default=1)]) class Model(BaseModel): x: MyAlias # This is not allowed ``` === "Python 3.12 and above (new syntax)" ```python {requires="3.12" upgrade="skip" lint="skip" test="skip"} from typing import Annotated from pydantic import BaseModel, Field type MyAlias = Annotated[int, Field(default=1)] class Model(BaseModel): x: MyAlias # This is not allowed ``` Only metadata that can be applied to the annotated type itself is allowed (e.g. [validation constraints](./fields.md#field-constraints) and JSON metadata). Trying to support field-specific metadata would require eagerly inspecting the type alias's [`__value__`][typing.TypeAliasType.__value__], and as such Pydantic wouldn't be able to have the alias stored as a JSON Schema definition. !!! note As with implicit type aliases, [type variables][typing.TypeVar] can also be used inside the generic alias: === "Python 3.9 and above" ```python from typing import Annotated, TypeVar from annotated_types import Len from typing_extensions import TypeAliasType T = TypeVar('T') ShortList = TypeAliasType( 'ShortList', Annotated[list[T], Len(max_length=4)], type_params=(T,) ) ``` === "Python 3.12 and above (new syntax)" ```python {requires="3.12" upgrade="skip" lint="skip"} from typing import Annotated, TypeVar from annotated_types import Len type ShortList[T] = Annotated[list[T], Len(max_length=4)] ``` #### Named recursive types Named type aliases should be used whenever you need to define recursive type aliases (1). { .annotate } 1. For several reasons, Pydantic isn't able to support implicit recursive aliases. For instance, it won't be able to resolve [forward annotations](./forward_annotations.md) across modules. For instance, here is an example definition of a JSON type: === "Python 3.9 and above" ```python from typing import Union from typing_extensions import TypeAliasType from pydantic import TypeAdapter Json = TypeAliasType( 'Json', 'Union[dict[str, Json], list[Json], str, int, float, bool, None]', # (1)! ) ta = TypeAdapter(Json) print(ta.json_schema()) """ { '$defs': { 'Json': { 'anyOf': [ { 'additionalProperties': {'$ref': '#/$defs/Json'}, 'type': 'object', }, {'items': {'$ref': '#/$defs/Json'}, 'type': 'array'}, {'type': 'string'}, {'type': 'integer'}, {'type': 'number'}, {'type': 'boolean'}, {'type': 'null'}, ] } }, '$ref': '#/$defs/Json', } """ ``` 1. Wrapping the annotation in quotes is necessary as it is eagerly evaluated (and `Json` has yet to be defined). === "Python 3.12 and above (new syntax)" ```python {requires="3.12" upgrade="skip" lint="skip"} from pydantic import TypeAdapter type Json = dict[str, Json] | list[Json] | str | int | float | bool | None # (1)! ta = TypeAdapter(Json) print(ta.json_schema()) """ { '$defs': { 'Json': { 'anyOf': [ { 'additionalProperties': {'$ref': '#/$defs/Json'}, 'type': 'object', }, {'items': {'$ref': '#/$defs/Json'}, 'type': 'array'}, {'type': 'string'}, {'type': 'integer'}, {'type': 'number'}, {'type': 'boolean'}, {'type': 'null'}, ] } }, '$ref': '#/$defs/Json', } """ ``` 1. The value of a named type alias is lazily evaluated, so there's no need to use forward annotations. !!! tip Pydantic defines a [`JsonValue`][pydantic.types.JsonValue] type as a convenience. ### Customizing validation with `__get_pydantic_core_schema__` To do more extensive customization of how Pydantic handles custom classes, and in particular when you have access to the class or can subclass it, you can implement a special `__get_pydantic_core_schema__` to tell Pydantic how to generate the `pydantic-core` schema. While `pydantic` uses `pydantic-core` internally to handle validation and serialization, it is a new API for Pydantic V2, thus it is one of the areas most likely to be tweaked in the future and you should try to stick to the built-in constructs like those provided by `annotated-types`, `pydantic.Field`, or `BeforeValidator` and so on. You can implement `__get_pydantic_core_schema__` both on a custom type and on metadata intended to be put in `Annotated`. In both cases the API is middleware-like and similar to that of "wrap" validators: you get a `source_type` (which isn't necessarily the same as the class, in particular for generics) and a `handler` that you can call with a type to either call the next metadata in `Annotated` or call into Pydantic's internal schema generation. The simplest no-op implementation calls the handler with the type you are given, then returns that as the result. You can also choose to modify the type before calling the handler, modify the core schema returned by the handler, or not call the handler at all. #### As a method on a custom type The following is an example of a type that uses `__get_pydantic_core_schema__` to customize how it gets validated. This is equivalent to implementing `__get_validators__` in Pydantic V1. ```python from typing import Any from pydantic_core import CoreSchema, core_schema from pydantic import GetCoreSchemaHandler, TypeAdapter class Username(str): @classmethod def __get_pydantic_core_schema__( cls, source_type: Any, handler: GetCoreSchemaHandler ) -> CoreSchema: return core_schema.no_info_after_validator_function(cls, handler(str)) ta = TypeAdapter(Username) res = ta.validate_python('abc') assert isinstance(res, Username) assert res == 'abc' ``` See [JSON Schema](../concepts/json_schema.md) for more details on how to customize JSON schemas for custom types. #### As an annotation Often you'll want to parametrize your custom type by more than just generic type parameters (which you can do via the type system and will be discussed later). Or you may not actually care (or want to) make an instance of your subclass; you actually want the original type, just with some extra validation done. For example, if you were to implement `pydantic.AfterValidator` (see [Adding validation and serialization](#adding-validation-and-serialization)) yourself, you'd do something similar to the following: ```python from dataclasses import dataclass from typing import Annotated, Any, Callable from pydantic_core import CoreSchema, core_schema from pydantic import BaseModel, GetCoreSchemaHandler @dataclass(frozen=True) # (1)! class MyAfterValidator: func: Callable[[Any], Any] def __get_pydantic_core_schema__( self, source_type: Any, handler: GetCoreSchemaHandler ) -> CoreSchema: return core_schema.no_info_after_validator_function( self.func, handler(source_type) ) Username = Annotated[str, MyAfterValidator(str.lower)] class Model(BaseModel): name: Username assert Model(name='ABC').name == 'abc' # (2)! ``` 1. The `frozen=True` specification makes `MyAfterValidator` hashable. Without this, a union such as `Username | None` will raise an error. 2. Notice that type checkers will not complain about assigning `'ABC'` to `Username` like they did in the previous example because they do not consider `Username` to be a distinct type from `str`. #### Handling third-party types Another use case for the pattern in the previous section is to handle third party types. ```python from typing import Annotated, Any from pydantic_core import core_schema from pydantic import ( BaseModel, GetCoreSchemaHandler, GetJsonSchemaHandler, ValidationError, ) from pydantic.json_schema import JsonSchemaValue class ThirdPartyType: """ This is meant to represent a type from a third-party library that wasn't designed with Pydantic integration in mind, and so doesn't have a `pydantic_core.CoreSchema` or anything. """ x: int def __init__(self): self.x = 0 class _ThirdPartyTypePydanticAnnotation: @classmethod def __get_pydantic_core_schema__( cls, _source_type: Any, _handler: GetCoreSchemaHandler, ) -> core_schema.CoreSchema: """ We return a pydantic_core.CoreSchema that behaves in the following ways: * ints will be parsed as `ThirdPartyType` instances with the int as the x attribute * `ThirdPartyType` instances will be parsed as `ThirdPartyType` instances without any changes * Nothing else will pass validation * Serialization will always return just an int """ def validate_from_int(value: int) -> ThirdPartyType: result = ThirdPartyType() result.x = value return result from_int_schema = core_schema.chain_schema( [ core_schema.int_schema(), core_schema.no_info_plain_validator_function(validate_from_int), ] ) return core_schema.json_or_python_schema( json_schema=from_int_schema, python_schema=core_schema.union_schema( [ # check if it's an instance first before doing any further work core_schema.is_instance_schema(ThirdPartyType), from_int_schema, ] ), serialization=core_schema.plain_serializer_function_ser_schema( lambda instance: instance.x ), ) @classmethod def __get_pydantic_json_schema__( cls, _core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler ) -> JsonSchemaValue: # Use the same schema that would be used for `int` return handler(core_schema.int_schema()) # We now create an `Annotated` wrapper that we'll use as the annotation for fields on `BaseModel`s, etc. PydanticThirdPartyType = Annotated[ ThirdPartyType, _ThirdPartyTypePydanticAnnotation ] # Create a model class that uses this annotation as a field class Model(BaseModel): third_party_type: PydanticThirdPartyType # Demonstrate that this field is handled correctly, that ints are parsed into `ThirdPartyType`, and that # these instances are also "dumped" directly into ints as expected. m_int = Model(third_party_type=1) assert isinstance(m_int.third_party_type, ThirdPartyType) assert m_int.third_party_type.x == 1 assert m_int.model_dump() == {'third_party_type': 1} # Do the same thing where an instance of ThirdPartyType is passed in instance = ThirdPartyType() assert instance.x == 0 instance.x = 10 m_instance = Model(third_party_type=instance) assert isinstance(m_instance.third_party_type, ThirdPartyType) assert m_instance.third_party_type.x == 10 assert m_instance.model_dump() == {'third_party_type': 10} # Demonstrate that validation errors are raised as expected for invalid inputs try: Model(third_party_type='a') except ValidationError as e: print(e) """ 2 validation errors for Model third_party_type.is-instance[ThirdPartyType] Input should be an instance of ThirdPartyType [type=is_instance_of, input_value='a', input_type=str] third_party_type.chain[int,function-plain[validate_from_int()]] Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str] """ assert Model.model_json_schema() == { 'properties': { 'third_party_type': {'title': 'Third Party Type', 'type': 'integer'} }, 'required': ['third_party_type'], 'title': 'Model', 'type': 'object', } ``` You can use this approach to e.g. define behavior for Pandas or Numpy types. #### Using `GetPydanticSchema` to reduce boilerplate ??? api "API Documentation" [`pydantic.types.GetPydanticSchema`][pydantic.types.GetPydanticSchema]
You may notice that the above examples where we create a marker class require a good amount of boilerplate. For many simple cases you can greatly minimize this by using `pydantic.GetPydanticSchema`: ```python from typing import Annotated from pydantic_core import core_schema from pydantic import BaseModel, GetPydanticSchema class Model(BaseModel): y: Annotated[ str, GetPydanticSchema( lambda tp, handler: core_schema.no_info_after_validator_function( lambda x: x * 2, handler(tp) ) ), ] assert Model(y='ab').y == 'abab' ``` #### Summary Let's recap: 1. Pydantic provides high level hooks to customize types via `Annotated` like `AfterValidator` and `Field`. Use these when possible. 2. Under the hood these use `pydantic-core` to customize validation, and you can hook into that directly using `GetPydanticSchema` or a marker class with `__get_pydantic_core_schema__`. 3. If you really want a custom type you can implement `__get_pydantic_core_schema__` on the type itself. ### Handling custom generic classes !!! warning This is an advanced technique that you might not need in the beginning. In most of the cases you will probably be fine with standard Pydantic models. You can use [Generic Classes](https://docs.python.org/3/library/typing.html#typing.Generic) as field types and perform custom validation based on the "type parameters" (or sub-types) with `__get_pydantic_core_schema__`. If the Generic class that you are using as a sub-type has a classmethod `__get_pydantic_core_schema__`, you don't need to use [`arbitrary_types_allowed`][pydantic.config.ConfigDict.arbitrary_types_allowed] for it to work. Because the `source_type` parameter is not the same as the `cls` parameter, you can use `typing.get_args` (or `typing_extensions.get_args`) to extract the generic parameters. Then you can use the `handler` to generate a schema for them by calling `handler.generate_schema`. Note that we do not do something like `handler(get_args(source_type)[0])` because we want to generate an unrelated schema for that generic parameter, not one that is influenced by the current context of `Annotated` metadata and such. This is less important for custom types, but crucial for annotated metadata that modifies schema building. ```python from dataclasses import dataclass from typing import Any, Generic, TypeVar from pydantic_core import CoreSchema, core_schema from typing_extensions import get_args, get_origin from pydantic import ( BaseModel, GetCoreSchemaHandler, ValidationError, ValidatorFunctionWrapHandler, ) ItemType = TypeVar('ItemType') # This is not a pydantic model, it's an arbitrary generic class @dataclass class Owner(Generic[ItemType]): name: str item: ItemType @classmethod def __get_pydantic_core_schema__( cls, source_type: Any, handler: GetCoreSchemaHandler ) -> CoreSchema: origin = get_origin(source_type) if origin is None: # used as `x: Owner` without params origin = source_type item_tp = Any else: item_tp = get_args(source_type)[0] # both calling handler(...) and handler.generate_schema(...) # would work, but prefer the latter for conceptual and consistency reasons item_schema = handler.generate_schema(item_tp) def val_item( v: Owner[Any], handler: ValidatorFunctionWrapHandler ) -> Owner[Any]: v.item = handler(v.item) return v python_schema = core_schema.chain_schema( # `chain_schema` means do the following steps in order: [ # Ensure the value is an instance of Owner core_schema.is_instance_schema(cls), # Use the item_schema to validate `items` core_schema.no_info_wrap_validator_function( val_item, item_schema ), ] ) return core_schema.json_or_python_schema( # for JSON accept an object with name and item keys json_schema=core_schema.chain_schema( [ core_schema.typed_dict_schema( { 'name': core_schema.typed_dict_field( core_schema.str_schema() ), 'item': core_schema.typed_dict_field(item_schema), } ), # after validating the json data convert it to python core_schema.no_info_before_validator_function( lambda data: Owner( name=data['name'], item=data['item'] ), # note that we reuse the same schema here as below python_schema, ), ] ), python_schema=python_schema, ) class Car(BaseModel): color: str class House(BaseModel): rooms: int class Model(BaseModel): car_owner: Owner[Car] home_owner: Owner[House] model = Model( car_owner=Owner(name='John', item=Car(color='black')), home_owner=Owner(name='James', item=House(rooms=3)), ) print(model) """ car_owner=Owner(name='John', item=Car(color='black')) home_owner=Owner(name='James', item=House(rooms=3)) """ try: # If the values of the sub-types are invalid, we get an error Model( car_owner=Owner(name='John', item=House(rooms=3)), home_owner=Owner(name='James', item=Car(color='black')), ) except ValidationError as e: print(e) """ 2 validation errors for Model wine Input should be a valid number, unable to parse string as a number [type=float_parsing, input_value='Kinda good', input_type=str] cheese Input should be a valid boolean, unable to interpret input [type=bool_parsing, input_value='yeah', input_type=str] """ # Similarly with JSON model = Model.model_validate_json( '{"car_owner":{"name":"John","item":{"color":"black"}},"home_owner":{"name":"James","item":{"rooms":3}}}' ) print(model) """ car_owner=Owner(name='John', item=Car(color='black')) home_owner=Owner(name='James', item=House(rooms=3)) """ try: Model.model_validate_json( '{"car_owner":{"name":"John","item":{"rooms":3}},"home_owner":{"name":"James","item":{"color":"black"}}}' ) except ValidationError as e: print(e) """ 2 validation errors for Model car_owner.item.color Field required [type=missing, input_value={'rooms': 3}, input_type=dict] home_owner.item.rooms Field required [type=missing, input_value={'color': 'black'}, input_type=dict] """ ``` #### Generic containers The same idea can be applied to create generic container types, like a custom `Sequence` type: ```python from collections.abc import Sequence from typing import Any, TypeVar from pydantic_core import ValidationError, core_schema from typing_extensions import get_args from pydantic import BaseModel, GetCoreSchemaHandler T = TypeVar('T') class MySequence(Sequence[T]): def __init__(self, v: Sequence[T]): self.v = v def __getitem__(self, i): return self.v[i] def __len__(self): return len(self.v) @classmethod def __get_pydantic_core_schema__( cls, source: Any, handler: GetCoreSchemaHandler ) -> core_schema.CoreSchema: instance_schema = core_schema.is_instance_schema(cls) args = get_args(source) if args: # replace the type and rely on Pydantic to generate the right schema # for `Sequence` sequence_t_schema = handler.generate_schema(Sequence[args[0]]) else: sequence_t_schema = handler.generate_schema(Sequence) non_instance_schema = core_schema.no_info_after_validator_function( MySequence, sequence_t_schema ) return core_schema.union_schema([instance_schema, non_instance_schema]) class M(BaseModel): model_config = dict(validate_default=True) s1: MySequence = [3] m = M() print(m) #> s1=<__main__.MySequence object at 0x0123456789ab> print(m.s1.v) #> [3] class M(BaseModel): s1: MySequence[int] M(s1=[1]) try: M(s1=['a']) except ValidationError as exc: print(exc) """ 2 validation errors for M s1.is-instance[MySequence] Input should be an instance of MySequence [type=is_instance_of, input_value=['a'], input_type=list] s1.function-after[MySequence(), json-or-python[json=list[int],python=chain[is-instance[Sequence],function-wrap[sequence_validator()]]]].0 Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str] """ ``` ### Access to field name !!!note This was not possible with Pydantic V2 to V2.3, it was [re-added](https://github.com/pydantic/pydantic/pull/7542) in Pydantic V2.4. As of Pydantic V2.4, you can access the field name via the `handler.field_name` within `__get_pydantic_core_schema__` and thereby set the field name which will be available from `info.field_name`. ```python from typing import Any from pydantic_core import core_schema from pydantic import BaseModel, GetCoreSchemaHandler, ValidationInfo class CustomType: """Custom type that stores the field it was used in.""" def __init__(self, value: int, field_name: str): self.value = value self.field_name = field_name def __repr__(self): return f'CustomType<{self.value} {self.field_name!r}>' @classmethod def validate(cls, value: int, info: ValidationInfo): return cls(value, info.field_name) @classmethod def __get_pydantic_core_schema__( cls, source_type: Any, handler: GetCoreSchemaHandler ) -> core_schema.CoreSchema: return core_schema.with_info_after_validator_function( cls.validate, handler(int) ) class MyModel(BaseModel): my_field: CustomType m = MyModel(my_field=1) print(m.my_field) #> CustomType<1 'my_field'> ``` You can also access `field_name` from the markers used with `Annotated`, like [`AfterValidator`][pydantic.functional_validators.AfterValidator]. ```python from typing import Annotated from pydantic import AfterValidator, BaseModel, ValidationInfo def my_validators(value: int, info: ValidationInfo): return f'<{value} {info.field_name!r}>' class MyModel(BaseModel): my_field: Annotated[int, AfterValidator(my_validators)] m = MyModel(my_field=1) print(m.my_field) #> <1 'my_field'> ``` pydantic-pydantic-ba0aa01/docs/concepts/unions.md000066400000000000000000000543311517143232300222170ustar00rootroot00000000000000Unions are fundamentally different to all other types Pydantic validates - instead of requiring all fields/items/values to be valid, unions require only one member to be valid. This leads to some nuance around how to validate unions: * which member(s) of the union should you validate data against, and in which order? * which errors to raise when validation fails? Validating unions feels like adding another orthogonal dimension to the validation process. To solve these problems, Pydantic supports three fundamental approaches to validating unions: 1. [left to right mode](#left-to-right-mode) - the simplest approach, each member of the union is tried in order and the first match is returned 2. [smart mode](#smart-mode) - similar to "left to right mode" members are tried in order; however, validation will proceed past the first match to attempt to find a better match, this is the default mode for most union validation 3. [discriminated unions](#discriminated-unions) - only one member of the union is tried, based on a discriminator !!! tip In general, we recommend using [discriminated unions](#discriminated-unions). They are both more performant and more predictable than untagged unions, as they allow you to control which member of the union to validate against. For complex cases, if you're using untagged unions, it's recommended to use `union_mode='left_to_right'` if you need guarantees about the order of validation attempts against the union members. If you're looking for incredibly specialized behavior, you can use a [custom validator](../concepts/validators.md#field-validators). ## Union Modes ### Left to Right Mode !!! note Because this mode often leads to unexpected validation results, it is not the default in Pydantic >=2, instead `union_mode='smart'` is the default. With this approach, validation is attempted against each member of the union in their order they're defined, and the first successful validation is accepted as input. If validation fails on all members, the validation error includes the errors from all members of the union. `union_mode='left_to_right'` must be set as a [`Field`](../concepts/fields.md) parameter on union fields where you want to use it. ```python {title="Union with left to right mode"} from typing import Union from pydantic import BaseModel, Field, ValidationError class User(BaseModel): id: Union[str, int] = Field(union_mode='left_to_right') print(User(id=123)) #> id=123 print(User(id='hello')) #> id='hello' try: User(id=[]) except ValidationError as e: print(e) """ 2 validation errors for User id.str Input should be a valid string [type=string_type, input_value=[], input_type=list] id.int Input should be a valid integer [type=int_type, input_value=[], input_type=list] """ ``` The order of members is very important in this case, as demonstrated by tweak the above example: ```python {title="Union with left to right - unexpected results"} from typing import Union from pydantic import BaseModel, Field class User(BaseModel): id: Union[int, str] = Field(union_mode='left_to_right') print(User(id=123)) # (1) #> id=123 print(User(id='456')) # (2) #> id=456 ``` 1. As expected the input is validated against the `int` member and the result is as expected. 2. We're in lax mode and the numeric string `'123'` is valid as input to the first member of the union, `int`. Since that is tried first, we get the surprising result of `id` being an `int` instead of a `str`. ### Smart Mode Because of the potentially surprising results of `union_mode='left_to_right'`, in Pydantic >=2 the default mode for `Union` validation is `union_mode='smart'`. In this mode, pydantic attempts to select the best match for the input from the union members. The exact algorithm may change between Pydantic minor releases to allow for improvements in both performance and accuracy. !!! note We reserve the right to tweak the internal `smart` matching algorithm in future versions of Pydantic. If you rely on very specific matching behavior, it's recommended to use `union_mode='left_to_right'` or [discriminated unions](#discriminated-unions). ??? info "Smart Mode Algorithm" The smart mode algorithm uses two metrics to determine the best match for the input: 1. The number of valid fields set (relevant for models, dataclasses, and typed dicts) 2. The exactness of the match (relevant for all types) #### Number of valid fields set !!! note This metric was introduced in Pydantic v2.8.0. Prior to this version, only exactness was used to determine the best match. This metric is currently only relevant for models, dataclasses, and typed dicts. The greater the number of valid fields set, the better the match. The number of fields set on nested models is also taken into account. These counts bubble up to the top-level union, where the union member with the highest count is considered the best match. For data types where this metric is relevant, we prioritize this count over exactness. For all other types, we use solely exactness. #### Exactness For `exactness`, Pydantic scores a match of a union member into one of the following three groups (from highest score to lowest score): * An exact type match, for example an `int` input to a `float | int` union validation is an exact type match for the `int` member * Validation would have succeeded in [`strict` mode](../concepts/strict_mode.md) * Validation would have succeeded in lax mode The union match which produced the highest exactness score will be considered the best match. In smart mode, the following steps are taken to try to select the best match for the input: === "`BaseModel`, `dataclass`, and `TypedDict`" 1. Union members are attempted left to right, with any successful matches scored into one of the three exactness categories described above, with the valid fields set count also tallied. 2. After all members have been evaluated, the member with the highest "valid fields set" count is returned. 3. If there's a tie for the highest "valid fields set" count, the exactness score is used as a tiebreaker, and the member with the highest exactness score is returned. 4. If validation failed on all the members, return all the errors. === "All other data types" 1. Union members are attempted left to right, with any successful matches scored into one of the three exactness categories described above. * If validation succeeds with an exact type match, that member is returned immediately and following members will not be attempted. 2. If validation succeeded on at least one member as a "strict" match, the leftmost of those "strict" matches is returned. 3. If validation succeeded on at least one member in "lax" mode, the leftmost match is returned. 4. Validation failed on all the members, return all the errors. ```python from typing import Union from uuid import UUID 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) #> id=123 name='John Doe' print(user_01.id) #> 123 user_02 = User(id='1234', name='John Doe') print(user_02) #> 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) #> 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 ``` ## Discriminated unions **Discriminated unions are sometimes referred to as "Tagged unions".** Unions can be validated more efficiently using a discriminator, by specifically choosing which member of the union to validate against. This makes validation more efficient and also avoids a proliferation of errors when validation fails. Adding discriminator to unions also means the generated JSON schema implements the `discriminator` attribute from the [OpenAPI specification](https://swagger.io/specification/#discriminator-object). [](){#discriminated-unions-with-str-discriminators} ### Discriminated unions with string discriminators Frequently, in the case of a union with multiple models, there is a common field to all members of the union that can be used to distinguish which union case the data should be validated against. To validate models based on that information, you can set a common field on each model of the union (`pet_type` in the example below), typed as accepting one or multiple literal values. When defining the discriminated union type, the `discriminator` parameter of [the `Field()` function](./fields.md) must be specified (the [`Discriminator`][pydantic.Discriminator] type can also be used). ```python from typing import Literal, Union from pydantic import BaseModel, Field, ValidationError class Cat(BaseModel): pet_type: Literal['cat'] meows: int class Dog(BaseModel): pet_type: Literal['dog'] barks: float class Lizard(BaseModel): pet_type: Literal['reptile', 'lizard'] scales: bool class Model(BaseModel): pet: Union[Cat, Dog, Lizard] = Field(discriminator='pet_type') n: int print(Model(pet={'pet_type': 'dog', 'barks': 3.14}, n=1)) #> pet=Dog(pet_type='dog', barks=3.14) n=1 try: Model(pet={'pet_type': 'dog'}, n=1) except ValidationError as e: print(e) """ 1 validation error for Model pet.dog.barks Field required [type=missing, input_value={'pet_type': 'dog'}, input_type=dict] """ ``` /// version-added | v2.13 [Root models](./models.md#rootmodel-and-custom-root-types) with a [`Literal`][typing.Literal] root type can be used in place of [`Literal`][typing.Literal] types. /// ### Discriminated Unions with callable `Discriminator` ??? api "API Documentation" [`pydantic.types.Discriminator`][pydantic.types.Discriminator]
In the case of a `Union` with multiple models, sometimes there isn't a single uniform field across all models that you can use as a discriminator. This is the perfect use case for a callable `Discriminator`. !!! tip When you're designing callable discriminators, remember that you might have to account for both `dict` and model type inputs. This pattern is similar to that of `mode='before'` validators, where you have to anticipate various forms of input. But wait! You ask, I only anticipate passing in `dict` types, why do I need to account for models? Pydantic uses callable discriminators for serialization as well, at which point the input to your callable is very likely to be a model instance. In the following examples, you'll see that the callable discriminators are designed to handle both `dict` and model inputs. If you don't follow this practice, it's likely that you'll, in the best case, get warnings during serialization, and in the worst case, get runtime errors during validation. ```python from typing import Annotated, Any, Literal, Optional, Union from pydantic import BaseModel, Discriminator, Tag class Pie(BaseModel): time_to_cook: int num_ingredients: int class ApplePie(Pie): fruit: Literal['apple'] = 'apple' class PumpkinPie(Pie): filling: Literal['pumpkin'] = 'pumpkin' def get_discriminator_value(v: Any) -> Optional[str]: if isinstance(v, dict): return v.get('fruit', v.get('filling')) return getattr(v, 'fruit', getattr(v, 'filling', None)) class ThanksgivingDinner(BaseModel): dessert: Annotated[ Union[ Annotated[ApplePie, Tag('apple')], Annotated[PumpkinPie, Tag('pumpkin')], ], Discriminator(get_discriminator_value), ] apple_variation = ThanksgivingDinner.model_validate( {'dessert': {'fruit': 'apple', 'time_to_cook': 60, 'num_ingredients': 8}} ) print(repr(apple_variation)) """ ThanksgivingDinner(dessert=ApplePie(time_to_cook=60, num_ingredients=8, fruit='apple')) """ pumpkin_variation = ThanksgivingDinner.model_validate( { 'dessert': { 'filling': 'pumpkin', 'time_to_cook': 40, 'num_ingredients': 6, } } ) print(repr(pumpkin_variation)) """ ThanksgivingDinner(dessert=PumpkinPie(time_to_cook=40, num_ingredients=6, filling='pumpkin')) """ ``` `Discriminator`s can also be used to validate `Union` types with combinations of models and primitive types. For example: ```python from typing import Annotated, Any, Optional, Union from pydantic import BaseModel, Discriminator, Tag, ValidationError def model_x_discriminator(v: Any) -> Optional[str]: if isinstance(v, int): return 'int' if isinstance(v, (dict, BaseModel)): return 'model' else: # return None if the discriminator value isn't found return None class SpecialValue(BaseModel): value: int class DiscriminatedModel(BaseModel): value: Annotated[ Union[ Annotated[int, Tag('int')], Annotated['SpecialValue', Tag('model')], ], Discriminator(model_x_discriminator), ] model_data = {'value': {'value': 1}} m = DiscriminatedModel.model_validate(model_data) print(m) #> value=SpecialValue(value=1) int_data = {'value': 123} m = DiscriminatedModel.model_validate(int_data) print(m) #> value=123 try: DiscriminatedModel.model_validate({'value': 'not an int or a model'}) except ValidationError as e: print(e) # (1)! """ 1 validation error for DiscriminatedModel value Unable to extract tag using discriminator model_x_discriminator() [type=union_tag_not_found, input_value='not an int or a model', input_type=str] """ ``` 1. Notice the callable discriminator function returns `None` if a discriminator value is not found. When `None` is returned, this `union_tag_not_found` error is raised. !!! note Using the [annotated pattern](./fields.md#the-annotated-pattern) can be handy to regroup the `Union` and `discriminator` information. See the next example for more details. There are a few ways to set a discriminator for a field, all varying slightly in syntax. For `str` discriminators: ```python {lint="skip" test="skip"} some_field: Union[...] = Field(discriminator='my_discriminator') some_field: Annotated[Union[...], Field(discriminator='my_discriminator')] ``` For callable `Discriminator`s: ```python {lint="skip" test="skip"} some_field: Union[...] = Field(discriminator=Discriminator(...)) some_field: Annotated[Union[...], Discriminator(...)] some_field: Annotated[Union[...], Field(discriminator=Discriminator(...))] ``` !!! warning Discriminated unions cannot be used with only a single variant, such as `Union[Cat]`. Python changes `Union[T]` into `T` at interpretation time, so it is not possible for `pydantic` to distinguish fields of `Union[T]` from `T`. ### Nested Discriminated Unions Only one discriminator can be set for a field but sometimes you want to combine multiple discriminators. You can do it by creating nested `Annotated` types, e.g.: ```python from typing import Annotated, Literal, Union from pydantic import BaseModel, Field, ValidationError class BlackCat(BaseModel): pet_type: Literal['cat'] color: Literal['black'] black_name: str class WhiteCat(BaseModel): pet_type: Literal['cat'] color: Literal['white'] white_name: str Cat = Annotated[Union[BlackCat, WhiteCat], Field(discriminator='color')] class Dog(BaseModel): pet_type: Literal['dog'] name: str Pet = Annotated[Union[Cat, Dog], Field(discriminator='pet_type')] class Model(BaseModel): pet: Pet n: int m = Model(pet={'pet_type': 'cat', 'color': 'black', 'black_name': 'felix'}, n=1) print(m) #> pet=BlackCat(pet_type='cat', color='black', black_name='felix') n=1 try: Model(pet={'pet_type': 'cat', 'color': 'red'}, n='1') except ValidationError as e: print(e) """ 1 validation error for Model pet.cat Input tag 'red' found using 'color' does not match any of the expected tags: 'black', 'white' [type=union_tag_invalid, input_value={'pet_type': 'cat', 'color': 'red'}, input_type=dict] """ try: Model(pet={'pet_type': 'cat', 'color': 'black'}, n='1') except ValidationError as e: print(e) """ 1 validation error for Model pet.cat.black.black_name Field required [type=missing, input_value={'pet_type': 'cat', 'color': 'black'}, input_type=dict] """ ``` !!! tip If you want to validate data against a union, and solely a union, you can use pydantic's [`TypeAdapter`](../concepts/type_adapter.md) construct instead of inheriting from the standard `BaseModel`. In the context of the previous example, we have the following: ```python {lint="skip" test="skip"} type_adapter = TypeAdapter(Pet) pet = type_adapter.validate_python( {'pet_type': 'cat', 'color': 'black', 'black_name': 'felix'} ) print(repr(pet)) #> BlackCat(pet_type='cat', color='black', black_name='felix') ``` ## Union Validation Errors When `Union` validation fails, error messages can be quite verbose, as they will produce validation errors for each case in the union. This is especially noticeable when dealing with recursive models, where reasons may be generated at each level of recursion. Discriminated unions help to simplify error messages in this case, as validation errors are only produced for the case with a matching discriminator value. You can also customize the error type, message, and context for a `Discriminator` by passing these specifications as parameters to the `Discriminator` constructor, as seen in the example below. ```python from typing import Annotated, Union from pydantic import BaseModel, Discriminator, Tag, ValidationError # Errors are quite verbose with a normal Union: class Model(BaseModel): x: Union[str, 'Model'] try: Model.model_validate({'x': {'x': {'x': 1}}}) except ValidationError as e: print(e) """ 4 validation errors for Model x.str Input should be a valid string [type=string_type, input_value={'x': {'x': 1}}, input_type=dict] x.Model.x.str Input should be a valid string [type=string_type, input_value={'x': 1}, input_type=dict] x.Model.x.Model.x.str Input should be a valid string [type=string_type, input_value=1, input_type=int] x.Model.x.Model.x.Model Input should be a valid dictionary or instance of Model [type=model_type, input_value=1, input_type=int] """ try: Model.model_validate({'x': {'x': {'x': {}}}}) except ValidationError as e: print(e) """ 4 validation errors for Model x.str Input should be a valid string [type=string_type, input_value={'x': {'x': {}}}, input_type=dict] x.Model.x.str Input should be a valid string [type=string_type, input_value={'x': {}}, input_type=dict] x.Model.x.Model.x.str Input should be a valid string [type=string_type, input_value={}, input_type=dict] x.Model.x.Model.x.Model.x Field required [type=missing, input_value={}, input_type=dict] """ # Errors are much simpler with a discriminated union: def model_x_discriminator(v): if isinstance(v, str): return 'str' if isinstance(v, (dict, BaseModel)): return 'model' class DiscriminatedModel(BaseModel): x: Annotated[ Union[ Annotated[str, Tag('str')], Annotated['DiscriminatedModel', Tag('model')], ], Discriminator( model_x_discriminator, custom_error_type='invalid_union_member', # (1)! custom_error_message='Invalid union member', # (2)! custom_error_context={'discriminator': 'str_or_model'}, # (3)! ), ] try: DiscriminatedModel.model_validate({'x': {'x': {'x': 1}}}) except ValidationError as e: print(e) """ 1 validation error for DiscriminatedModel x.model.x.model.x Invalid union member [type=invalid_union_member, input_value=1, input_type=int] """ try: DiscriminatedModel.model_validate({'x': {'x': {'x': {}}}}) except ValidationError as e: print(e) """ 1 validation error for DiscriminatedModel x.model.x.model.x.model.x Field required [type=missing, input_value={}, input_type=dict] """ # The data is still handled properly when valid: data = {'x': {'x': {'x': 'a'}}} m = DiscriminatedModel.model_validate(data) print(m.model_dump()) #> {'x': {'x': {'x': 'a'}}} ``` 1. `custom_error_type` is the `type` attribute of the `ValidationError` raised when validation fails. 2. `custom_error_message` is the `msg` attribute of the `ValidationError` raised when validation fails. 3. `custom_error_context` is the `ctx` attribute of the `ValidationError` raised when validation fails. You can also simplify error messages by labeling each case with a [`Tag`][pydantic.types.Tag]. This is especially useful when you have complex types like those in this example: ```python from typing import Annotated, Union from pydantic import AfterValidator, Tag, TypeAdapter, ValidationError DoubledList = Annotated[list[int], AfterValidator(lambda x: x * 2)] StringsMap = dict[str, str] # Not using any `Tag`s for each union case, the errors are not so nice to look at adapter = TypeAdapter(Union[DoubledList, StringsMap]) try: adapter.validate_python(['a']) except ValidationError as exc_info: print(exc_info) """ 2 validation errors for union[function-after[(), list[int]],dict[str,str]] function-after[(), list[int]].0 Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str] dict[str,str] Input should be a valid dictionary [type=dict_type, input_value=['a'], input_type=list] """ tag_adapter = TypeAdapter( Union[ Annotated[DoubledList, Tag('DoubledList')], Annotated[StringsMap, Tag('StringsMap')], ] ) try: tag_adapter.validate_python(['a']) except ValidationError as exc_info: print(exc_info) """ 2 validation errors for union[DoubledList,StringsMap] DoubledList.0 Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str] StringsMap Input should be a valid dictionary [type=dict_type, input_value=['a'], input_type=list] """ ``` pydantic-pydantic-ba0aa01/docs/concepts/validation_decorator.md000066400000000000000000000260711517143232300251000ustar00rootroot00000000000000??? api "API Documentation" [`pydantic.validate_call_decorator.validate_call`][pydantic.validate_call_decorator.validate_call]
The [`validate_call()`][pydantic.validate_call] decorator allows the arguments passed to a function to be parsed and validated using the function's annotations before the function is called. While under the hood this uses the same approach of model creation and initialisation (see [Validators](validators.md) for more details), it provides an extremely easy way to apply validation to your code with minimal boilerplate. Example of usage: ```python from pydantic import ValidationError, validate_call @validate_call def repeat(s: str, count: int, *, separator: bytes = b'') -> bytes: b = s.encode() return separator.join(b for _ in range(count)) a = repeat('hello', 3) print(a) #> b'hellohellohello' b = repeat('x', '4', separator=b' ') print(b) #> b'x x x x' try: c = repeat('hello', 'wrong') except ValidationError as exc: print(exc) """ 1 validation error for repeat 1 Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='wrong', input_type=str] """ ``` ## Parameter types Parameter types are inferred from type annotations on the function, or as [`Any`][typing.Any] if not annotated. All types listed in [types](types.md) can be validated, including Pydantic models and [custom types](types.md#custom-types). As with the rest of Pydantic, types are by default coerced by the decorator before they're passed to the actual function: ```python from datetime import date from pydantic import validate_call @validate_call def greater_than(d1: date, d2: date, *, include_equal=False) -> date: # (1)! if include_equal: return d1 >= d2 else: return d1 > d2 d1 = '2000-01-01' # (2)! d2 = date(2001, 1, 1) greater_than(d1, d2, include_equal=True) ``` 1. Because `include_equal` has no type annotation, it will be inferred as [`Any`][typing.Any]. 2. Although `d1` is a string, it will be converted to a [`date`][datetime.date] object. Type coercion like this can be extremely helpful, but also confusing or not desired (see [model data conversion](models.md#data-conversion)). [Strict mode](strict_mode.md) can be enabled by using a [custom configuration](#custom-configuration). !!! note "Validating the return value" By default, the return value of the function is **not** validated. To do so, the `validate_return` argument of the decorator can be set to `True`. ## Function signatures The [`validate_call()`][pydantic.validate_call] decorator is designed to work with functions using all possible [parameter configurations][parameter] and all possible combinations of these: * Positional or keyword parameters with or without defaults. * Keyword-only parameters: parameters after `*,`. * Positional-only parameters: parameters before `, /`. * Variable positional parameters defined via `*` (often `*args`). * Variable keyword parameters defined via `**` (often `**kwargs`). ??? example ```python from pydantic import validate_call @validate_call def pos_or_kw(a: int, b: int = 2) -> str: return f'a={a} b={b}' print(pos_or_kw(1, b=3)) #> a=1 b=3 @validate_call def kw_only(*, a: int, b: int = 2) -> str: return f'a={a} b={b}' print(kw_only(a=1)) #> a=1 b=2 print(kw_only(a=1, b=3)) #> a=1 b=3 @validate_call def pos_only(a: int, b: int = 2, /) -> str: return f'a={a} b={b}' print(pos_only(1)) #> a=1 b=2 @validate_call def var_args(*args: int) -> str: return str(args) print(var_args(1)) #> (1,) print(var_args(1, 2, 3)) #> (1, 2, 3) @validate_call def var_kwargs(**kwargs: int) -> str: return str(kwargs) print(var_kwargs(a=1)) #> {'a': 1} print(var_kwargs(a=1, b=2)) #> {'a': 1, 'b': 2} @validate_call def armageddon( a: int, /, b: int, *c: int, d: int, e: int = None, **f: int, ) -> str: return f'a={a} b={b} c={c} d={d} e={e} f={f}' print(armageddon(1, 2, d=3)) #> a=1 b=2 c=() d=3 e=None f={} print(armageddon(1, 2, 3, 4, 5, 6, d=8, e=9, f=10, spam=11)) #> a=1 b=2 c=(3, 4, 5, 6) d=8 e=9 f={'f': 10, 'spam': 11} ``` !!! note "[`Unpack`][typing.Unpack] for keyword parameters" [`Unpack`][typing.Unpack] and typed dictionaries can be used to annotate the variable keyword parameters of a function: ```python from typing_extensions import TypedDict, Unpack from pydantic import validate_call class Point(TypedDict): x: int y: int @validate_call def add_coords(**kwargs: Unpack[Point]) -> int: return kwargs['x'] + kwargs['y'] add_coords(x=1, y=2) ``` For reference, see the [related specification section] and [PEP 692]. /// version-added | v2.10 /// [related specification section]: https://typing.readthedocs.io/en/latest/spec/callables.html#unpack-for-keyword-arguments [PEP 692]: https://peps.python.org/pep-0692/ ## Using the [`Field()`][pydantic.Field] function to describe function parameters The [`Field()` function](fields.md) can also be used with the decorator to provide extra information about the field and validations. If you don't make use of the `default` or `default_factory` parameter, it is recommended to use the [annotated pattern](./fields.md#the-annotated-pattern) (so that type checkers infer the parameter as being required). Otherwise, the [`Field()`][pydantic.Field] function can be used as a default value (again, to trick type checkers into thinking a default value is provided for the parameter). ```python from typing import Annotated from pydantic import Field, ValidationError, validate_call @validate_call def how_many(num: Annotated[int, Field(gt=10)]): return num try: how_many(1) except ValidationError as e: print(e) """ 1 validation error for how_many 0 Input should be greater than 10 [type=greater_than, input_value=1, input_type=int] """ @validate_call def return_value(value: str = Field(default='default value')): return value print(return_value()) #> default value ``` [Aliases](fields.md#field-aliases) can be used with the decorator as normal: ```python from typing import Annotated from pydantic import Field, validate_call @validate_call def how_many(num: Annotated[int, Field(gt=10, alias='number')]): return num how_many(number=42) ``` ## Accessing the original function The original function which was decorated can still be accessed by using the `raw_function` attribute. This is useful if in some scenarios you trust your input arguments and want to call the function in the most efficient way (see [notes on performance](#performance) below): ```python from pydantic import validate_call @validate_call def repeat(s: str, count: int, *, separator: bytes = b'') -> bytes: b = s.encode() return separator.join(b for _ in range(count)) a = repeat('hello', 3) print(a) #> b'hellohellohello' b = repeat.raw_function('good bye', 2, separator=b', ') print(b) #> b'good bye, good bye' ``` ## Async functions [`validate_call()`][pydantic.validate_call] can also be used on async functions: ```python class Connection: async def execute(self, sql, *args): return 'testing@example.com' conn = Connection() # ignore-above import asyncio from pydantic import PositiveInt, ValidationError, validate_call @validate_call async def get_user_email(user_id: PositiveInt): # `conn` is some fictional connection to a database email = await conn.execute('select email from users where id=$1', user_id) if email is None: raise RuntimeError('user not found') else: return email async def main(): email = await get_user_email(123) print(email) #> testing@example.com try: await get_user_email(-4) except ValidationError as exc: print(exc.errors()) """ [ { 'type': 'greater_than', 'loc': (0,), 'msg': 'Input should be greater than 0', 'input': -4, 'ctx': {'gt': 0}, 'url': 'https://errors.pydantic.dev/2/v/greater_than', } ] """ asyncio.run(main()) # requires: `conn.execute()` that will return `'testing@example.com'` ``` ## Compatibility with type checkers As the [`validate_call()`][pydantic.validate_call] decorator preserves the decorated function's signature, it should be compatible with type checkers (such as mypy and pyright). However, due to current limitations in the Python type system, the [`raw_function`](#accessing-the-original-function) or other attributes won't be recognized and you will need to suppress the error using (usually with a `# type: ignore` comment). ## Custom configuration Similarly to Pydantic models, the `config` parameter of the decorator can be used to specify a custom configuration: ```python from pydantic import ConfigDict, ValidationError, validate_call class Foobar: def __init__(self, v: str): self.v = v def __add__(self, other: 'Foobar') -> str: return f'{self} + {other}' def __str__(self) -> str: return f'Foobar({self.v})' @validate_call(config=ConfigDict(arbitrary_types_allowed=True)) def add_foobars(a: Foobar, b: Foobar): return a + b c = add_foobars(Foobar('a'), Foobar('b')) print(c) #> Foobar(a) + Foobar(b) try: add_foobars(1, 2) except ValidationError as e: print(e) """ 2 validation errors for add_foobars 0 Input should be an instance of Foobar [type=is_instance_of, input_value=1, input_type=int] 1 Input should be an instance of Foobar [type=is_instance_of, input_value=2, input_type=int] """ ``` ## Extension — validating arguments before calling a function In some cases, it may be helpful to separate validation of a function's arguments from the function call itself. This might be useful when a particular function is costly/time consuming. Here's an example of a workaround you can use for that pattern: ```python from pydantic import validate_call @validate_call def validate_foo(a: int, b: int): def foo(): return a + b return foo foo = validate_foo(a=1, b=2) print(foo()) #> 3 ``` ## Limitations ### Validation exception Currently upon validation failure, a standard Pydantic [`ValidationError`][pydantic_core.ValidationError] is raised (see [model error handling](models.md#error-handling) for details). This is also true for missing required arguments, where Python normally raises a [`TypeError`][]. ### Performance We've made a big effort to make Pydantic as performant as possible. While the inspection of the decorated function is only performed once, there will still be a performance impact when making calls to the function compared to using the original function. In many situations, this will have little or no noticeable effect. However, be aware that [`validate_call()`][pydantic.validate_call] is not an equivalent or alternative to function definitions in strongly typed languages, and it never will be. pydantic-pydantic-ba0aa01/docs/concepts/validators.md000066400000000000000000000730341517143232300230550ustar00rootroot00000000000000In addition to Pydantic's [built-in validation capabilities](./fields.md#field-constraints), you can leverage custom validators at the field and model levels to enforce more complex constraints and ensure the integrity of your data. !!! tip Want to quickly jump to the relevant validator section?
* Field validators --- * [field *after* validators](#field-after-validator) * [field *before* validators](#field-before-validator) * [field *plain* validators](#field-plain-validator) * [field *wrap* validators](#field-wrap-validator) * Model validators --- * [model *before* validators](#model-before-validator) * [model *after* validators](#model-after-validator) * [model *wrap* validators](#model-wrap-validator)
## Field validators ??? api "API Documentation" [`pydantic.functional_validators.WrapValidator`][pydantic.functional_validators.WrapValidator]
[`pydantic.functional_validators.PlainValidator`][pydantic.functional_validators.PlainValidator]
[`pydantic.functional_validators.BeforeValidator`][pydantic.functional_validators.BeforeValidator]
[`pydantic.functional_validators.AfterValidator`][pydantic.functional_validators.AfterValidator]
[`pydantic.functional_validators.field_validator`][pydantic.functional_validators.field_validator]
In its simplest form, a field validator is a callable taking the value to be validated as an argument and **returning the validated value**. The callable can perform checks for specific conditions (see [raising validation errors](#raising-validation-errors)) and make changes to the validated value (coercion or mutation). **Four** different types of validators can be used. They can all be defined using the [annotated pattern](./fields.md#the-annotated-pattern) or using the [`@field_validator`][pydantic.field_validator] decorator, applied on a [class method][classmethod]: * ***After* validators**: run after Pydantic's internal validation. They are generally more type safe and thus easier to implement. {#field-after-validator} === "Annotated pattern" Here is an example of a validator performing a validation check, and returning the value unchanged. ```python from typing import Annotated from pydantic import AfterValidator, BaseModel, ValidationError def is_even(value: int) -> int: if value % 2 == 1: raise ValueError(f'{value} is not an even number') return value # (1)! class Model(BaseModel): number: Annotated[int, AfterValidator(is_even)] try: Model(number=1) except ValidationError as err: print(err) """ 1 validation error for Model number Value error, 1 is not an even number [type=value_error, input_value=1, input_type=int] """ ``` 1. Note that it is important to return the validated value. === "Decorator" Here is an example of a validator performing a validation check, and returning the value unchanged, this time using the [`field_validator()`][pydantic.field_validator] decorator. ```python from pydantic import BaseModel, ValidationError, field_validator class Model(BaseModel): number: int @field_validator('number', mode='after') # (1)! @classmethod def is_even(cls, value: int) -> int: if value % 2 == 1: raise ValueError(f'{value} is not an even number') return value # (2)! try: Model(number=1) except ValidationError as err: print(err) """ 1 validation error for Model number Value error, 1 is not an even number [type=value_error, input_value=1, input_type=int] """ ``` 1. `'after'` is the default mode for the decorator, and can be omitted. 2. Note that it is important to return the validated value. ??? example "Example mutating the value" Here is an example of a validator making changes to the validated value (no exception is raised). === "Annotated pattern" ```python from typing import Annotated from pydantic import AfterValidator, BaseModel def double_number(value: int) -> int: return value * 2 class Model(BaseModel): number: Annotated[int, AfterValidator(double_number)] print(Model(number=2)) #> number=4 ``` === "Decorator" ```python from pydantic import BaseModel, field_validator class Model(BaseModel): number: int @field_validator('number', mode='after') # (1)! @classmethod def double_number(cls, value: int) -> int: return value * 2 print(Model(number=2)) #> number=4 ``` 1. `'after'` is the default mode for the decorator, and can be omitted. * ***Before* validators**: run before Pydantic's internal parsing and validation (e.g. coercion of a `str` to an `int`). These are more flexible than [*after* validators](#field-after-validator), but they also have to deal with the raw input, which in theory could be any arbitrary object. You should also avoid mutating the value directly if you are raising a [validation error](#raising-validation-errors) later in your validator function, as the mutated value may be passed to other validators if using [unions](./unions.md). {#field-before-validator} The value returned from this callable is then validated against the provided type annotation by Pydantic. === "Annotated pattern" ```python from typing import Annotated, Any from pydantic import BaseModel, BeforeValidator, ValidationError def ensure_list(value: Any) -> Any: # (1)! if not isinstance(value, list): # (2)! return [value] else: return value class Model(BaseModel): numbers: Annotated[list[int], BeforeValidator(ensure_list)] print(Model(numbers=2)) #> numbers=[2] try: Model(numbers='str') except ValidationError as err: print(err) # (3)! """ 1 validation error for Model numbers.0 Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='str', input_type=str] """ ``` 1. Notice the use of [`Any`][typing.Any] as a type hint for `value`. *Before* validators take the raw input, which can be anything. 2. Note that you might want to check for other sequence types (such as tuples) that would normally successfully validate against the `list` type. *Before* validators give you more flexibility, but you have to account for every possible case. 3. Pydantic still performs validation against the `int` type, no matter if our `ensure_list` validator did operations on the original input type. === "Decorator" ```python from typing import Any from pydantic import BaseModel, ValidationError, field_validator class Model(BaseModel): numbers: list[int] @field_validator('numbers', mode='before') @classmethod def ensure_list(cls, value: Any) -> Any: # (1)! if not isinstance(value, list): # (2)! return [value] else: return value print(Model(numbers=2)) #> numbers=[2] try: Model(numbers='str') except ValidationError as err: print(err) # (3)! """ 1 validation error for Model numbers.0 Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='str', input_type=str] """ ``` 1. Notice the use of [`Any`][typing.Any] as a type hint for `value`. *Before* validators take the raw input, which can be anything. 2. Note that you might want to check for other sequence types (such as tuples) that would normally successfully validate against the `list` type. *Before* validators give you more flexibility, but you have to account for every possible case. 3. Pydantic still performs validation against the `int` type, no matter if our `ensure_list` validator did operations on the original input type. * ***Plain* validators**: act similarly to *before* validators but they **terminate validation immediately** after returning, so no further validators are called and Pydantic does not do any of its internal validation against the field type. {#field-plain-validator} === "Annotated pattern" ```python from typing import Annotated, Any from pydantic import BaseModel, PlainValidator def val_number(value: Any) -> Any: if isinstance(value, int): return value * 2 else: return value class Model(BaseModel): number: Annotated[int, PlainValidator(val_number)] print(Model(number=4)) #> number=8 print(Model(number='invalid')) # (1)! #> number='invalid' ``` 1. Although `'invalid'` shouldn't validate against the `int` type, Pydantic accepts the input. === "Decorator" ```python from typing import Any from pydantic import BaseModel, field_validator class Model(BaseModel): number: int @field_validator('number', mode='plain') @classmethod def val_number(cls, value: Any) -> Any: if isinstance(value, int): return value * 2 else: return value print(Model(number=4)) #> number=8 print(Model(number='invalid')) # (1)! #> number='invalid' ``` 1. Although `'invalid'` shouldn't validate against the `int` type, Pydantic accepts the input. * ***Wrap* validators**: are the most flexible of all. You can run code before or after Pydantic and other validators process the input, or you can terminate validation immediately, either by returning the value early or by raising an error. {#field-wrap-validator} Such validators must be defined with a **mandatory** extra *handler* parameter: a callable taking the value to be validated as an argument. Internally, this handler will delegate validation of the value to Pydantic. You are free to wrap the call to the handler in a [`try..except`][handling exceptions] block, or not call it at all. [handling exceptions]: https://docs.python.org/3/tutorial/errors.html#handling-exceptions === "Annotated pattern" ```python {lint="skip"} from typing import Any from typing import Annotated from pydantic import BaseModel, Field, ValidationError, ValidatorFunctionWrapHandler, WrapValidator def truncate(value: Any, handler: ValidatorFunctionWrapHandler) -> str: try: return handler(value) except ValidationError as err: if err.errors()[0]['type'] == 'string_too_long': return handler(value[:5]) else: raise class Model(BaseModel): my_string: Annotated[str, Field(max_length=5), WrapValidator(truncate)] print(Model(my_string='abcde')) #> my_string='abcde' print(Model(my_string='abcdef')) #> my_string='abcde' ``` === "Decorator" ```python {lint="skip"} from typing import Any from typing import Annotated from pydantic import BaseModel, Field, ValidationError, ValidatorFunctionWrapHandler, field_validator class Model(BaseModel): my_string: Annotated[str, Field(max_length=5)] @field_validator('my_string', mode='wrap') @classmethod def truncate(cls, value: Any, handler: ValidatorFunctionWrapHandler) -> str: try: return handler(value) except ValidationError as err: if err.errors()[0]['type'] == 'string_too_long': return handler(value[:5]) else: raise print(Model(my_string='abcde')) #> my_string='abcde' print(Model(my_string='abcdef')) #> my_string='abcde' ``` !!! note "Validation of default values" As mentioned in the [fields documentation](./fields.md#validate-default-values), default values of fields are *not* validated unless configured to do so, and thus custom validators will not be applied as well. ### Which validator pattern to use While both approaches can achieve the same thing, each pattern provides different benefits. #### Using the annotated pattern One of the key benefits of using the [annotated pattern](./fields.md#the-annotated-pattern) is to make validators reusable: ```python from typing import Annotated from pydantic import AfterValidator, BaseModel def is_even(value: int) -> int: if value % 2 == 1: raise ValueError(f'{value} is not an even number') return value EvenNumber = Annotated[int, AfterValidator(is_even)] class Model1(BaseModel): my_number: EvenNumber class Model2(BaseModel): other_number: Annotated[EvenNumber, AfterValidator(lambda v: v + 2)] class Model3(BaseModel): list_of_even_numbers: list[EvenNumber] # (1)! ``` 1. As mentioned in the [annotated pattern](./fields.md#the-annotated-pattern) documentation, we can also make use of validators for specific parts of the annotation (in this case, validation is applied for list items, but not the whole list). It is also easier to understand which validators are applied to a type, by just looking at the field annotation. #### Using the decorator pattern One of the key benefits of using the [`field_validator()`][pydantic.field_validator] decorator is to apply the function to multiple fields: ```python from pydantic import BaseModel, field_validator class Model(BaseModel): f1: str f2: str @field_validator('f1', 'f2', mode='before') @classmethod def capitalize(cls, value: str) -> str: return value.capitalize() ``` Here are a couple additional notes about the decorator usage: * If you want the validator to apply to all fields (including the ones defined in subclasses), you can pass `'*'` as the field name argument. * By default, the decorator will ensure the provided field name(s) are defined on the model. If you want to disable this check during class creation, you can do so by passing `False` to the `check_fields` argument. This is useful when the field validator is defined on a base class, and the field is expected to exist on subclasses. ## Model validators ??? api "API Documentation" [`pydantic.functional_validators.model_validator`][pydantic.functional_validators.model_validator]
Validation can also be performed on the entire model's data using the [`model_validator()`][pydantic.model_validator] decorator. **Three** different types of model validators can be used: * ***After* validators**: run after the whole model has been validated. As such, they are defined as *instance* methods and can be seen as post-initialization hooks. Important note: the validated instance should be returned. {#model-after-validator} ```python from typing_extensions import Self from pydantic import BaseModel, model_validator class UserModel(BaseModel): username: str password: str password_repeat: str @model_validator(mode='after') def check_passwords_match(self) -> Self: if self.password != self.password_repeat: raise ValueError('Passwords do not match') return self ``` * ***Before* validators**: are run before the model is instantiated. These are more flexible than *after* validators, but they also have to deal with the raw input, which in theory could be any arbitrary object. You should also avoid mutating the value directly if you are raising a [validation error](#raising-validation-errors) later in your validator function, as the mutated value may be passed to other validators if using [unions](./unions.md). {#model-before-validator} ```python from typing import Any from pydantic import BaseModel, model_validator class UserModel(BaseModel): username: str @model_validator(mode='before') @classmethod def check_card_number_not_present(cls, data: Any) -> Any: # (1)! if isinstance(data, dict): # (2)! if 'card_number' in data: raise ValueError("'card_number' should not be included") return data ``` 1. Notice the use of [`Any`][typing.Any] as a type hint for `data`. *Before* validators take the raw input, which can be anything. 2. Most of the time, the input data will be a dictionary (e.g. when calling `UserModel(username='...')`). However, this is not always the case. For instance, if the [`from_attributes`][pydantic.ConfigDict.from_attributes] configuration value is set, you might receive an arbitrary class instance for the `data` argument. * ***Wrap* validators**: are the most flexible of all. You can run code before or after Pydantic and other validators process the input data, or you can terminate validation immediately, either by returning the data early or by raising an error. {#model-wrap-validator} ```python {lint="skip"} import logging from typing import Any from typing_extensions import Self from pydantic import BaseModel, ModelWrapValidatorHandler, ValidationError, model_validator class UserModel(BaseModel): username: str @model_validator(mode='wrap') @classmethod def log_failed_validation(cls, data: Any, handler: ModelWrapValidatorHandler[Self]) -> Self: try: return handler(data) except ValidationError: logging.error('Model %s failed to validate with data %s', cls, data) raise ``` !!! note "On inheritance" A model validator defined in a base class will be called during the validation of a subclass instance. Overriding a model validator in a subclass will override the base class' validator, and thus only the subclass' version of said validator will be called. ## Raising validation errors To raise a validation error, three types of exceptions can be used: * [`ValueError`][]: this is the most common exception raised inside validators. * [`AssertionError`][]: using the [assert][] statement also works, but be aware that these statements are skipped when Python is run with the [-O][] optimization flag. * [`PydanticCustomError`][pydantic_core.PydanticCustomError]: a bit more verbose, but provides extra flexibility: ```python from pydantic_core import PydanticCustomError from pydantic import BaseModel, ValidationError, field_validator class Model(BaseModel): x: int @field_validator('x', mode='after') @classmethod def validate_x(cls, v: int) -> int: if v % 42 == 0: raise PydanticCustomError( 'the_answer_error', '{number} is the answer!', {'number': v}, ) return v try: Model(x=42 * 2) except ValidationError as e: print(e) """ 1 validation error for Model x 84 is the answer! [type=the_answer_error, input_value=84, input_type=int] """ ``` ## Validation info Both the field and model validators callables (in all modes) can optionally take an extra [`ValidationInfo`][pydantic.ValidationInfo] argument, providing useful extra information, such as: * [already validated data](#validation-data) * [user defined context](#validation-context) * the current [validation mode](./models.md#validating-data): either `'python'`, `'json'` or `'strings'` (see the [`mode`][pydantic.ValidationInfo.mode] property) * the current field name, if using a [field validator](#field-validators) (see the [`field_name`][pydantic.ValidationInfo.field_name] property). ### Validation data For field validators, the already validated data can be accessed using the [`data`][pydantic.ValidationInfo.data] property. Here is an example than can be used as an alternative to the [*after* model validator](#model-after-validator) example: ```python from pydantic import BaseModel, ValidationInfo, field_validator class UserModel(BaseModel): password: str password_repeat: str username: str @field_validator('password_repeat', mode='after') @classmethod def check_passwords_match(cls, value: str, info: ValidationInfo) -> str: if value != info.data['password']: raise ValueError('Passwords do not match') return value ``` !!! warning As validation is performed in the [order fields are defined](./models.md#field-ordering), you have to make sure you are not accessing a field that hasn't been validated yet. In the code above, for example, the `username` validated value is not available yet, as it is defined *after* `password_repeat`. The [`data`][pydantic.ValidationInfo.data] property is `None` for [model validators](#model-validators). ### Validation context You can pass a context object to the [validation methods](./models.md#validating-data), which can be accessed inside the validator functions using the [`context`][pydantic.ValidationInfo.context] property: ```python from pydantic import BaseModel, ValidationInfo, field_validator class Model(BaseModel): text: str @field_validator('text', mode='after') @classmethod def remove_stopwords(cls, v: str, info: ValidationInfo) -> str: if isinstance(info.context, dict): stopwords = info.context.get('stopwords', set()) v = ' '.join(w for w in v.split() if w.lower() not in stopwords) return v data = {'text': 'This is an example document'} print(Model.model_validate(data)) # no context #> text='This is an example document' print(Model.model_validate(data, context={'stopwords': ['this', 'is', 'an']})) #> text='example document' ``` Similarly, you can [use a context for serialization](../concepts/serialization.md#serialization-context). ??? note "Providing context when directly instantiating a model" It is currently not possible to provide a context when directly instantiating a model (i.e. when calling `Model(...)`). You can work around this through the use of a [`ContextVar`][contextvars.ContextVar] and a custom `__init__` method: ```python from __future__ import annotations from collections.abc import Generator from contextlib import contextmanager from contextvars import ContextVar from typing import Any from pydantic import BaseModel, ValidationInfo, field_validator _init_context_var = ContextVar('_init_context_var', default=None) @contextmanager def init_context(value: dict[str, Any]) -> Generator[None]: token = _init_context_var.set(value) try: yield finally: _init_context_var.reset(token) class Model(BaseModel): my_number: int def __init__(self, /, **data: Any) -> None: self.__pydantic_validator__.validate_python( data, self_instance=self, context=_init_context_var.get(), ) @field_validator('my_number') @classmethod def multiply_with_context(cls, value: int, info: ValidationInfo) -> int: if isinstance(info.context, dict): multiplier = info.context.get('multiplier', 1) value = value * multiplier return value print(Model(my_number=2)) #> my_number=2 with init_context({'multiplier': 3}): print(Model(my_number=2)) #> my_number=6 print(Model(my_number=2)) #> my_number=2 ``` ## Ordering of validators When using the [annotated pattern](#using-the-annotated-pattern), the order in which validators are applied is defined as follows: [*before*](#field-before-validator) and [*wrap*](#field-wrap-validator) validators are run from right to left, and [*after*](#field-after-validator) validators are then run from left to right: ```python {lint="skip" test="skip"} from pydantic import AfterValidator, BaseModel, BeforeValidator, WrapValidator class Model(BaseModel): name: Annotated[ str, AfterValidator(runs_3rd), AfterValidator(runs_4th), BeforeValidator(runs_2nd), WrapValidator(runs_1st), ] ``` Internally, validators defined using [the decorator](#using-the-decorator-pattern) are converted to their annotated form counterpart and added last after the existing metadata for the field. This means that the same ordering logic applies. ## Special types Pydantic provides a few special utilities that can be used to customize validation. * [`InstanceOf`][pydantic.functional_validators.InstanceOf] can be used to validate that a value is an instance of a given class. ```python from pydantic import BaseModel, InstanceOf, ValidationError class Fruit: def __repr__(self): return self.__class__.__name__ class Banana(Fruit): ... class Apple(Fruit): ... class Basket(BaseModel): fruits: list[InstanceOf[Fruit]] print(Basket(fruits=[Banana(), Apple()])) #> fruits=[Banana, Apple] try: Basket(fruits=[Banana(), 'Apple']) except ValidationError as e: print(e) """ 1 validation error for Basket fruits.1 Input should be an instance of Fruit [type=is_instance_of, input_value='Apple', input_type=str] """ ``` * [`SkipValidation`][pydantic.functional_validators.SkipValidation] can be used to skip validation on a field. ```python from pydantic import BaseModel, SkipValidation class Model(BaseModel): names: list[SkipValidation[str]] m = Model(names=['foo', 'bar']) print(m) #> names=['foo', 'bar'] m = Model(names=['foo', 123]) # (1)! print(m) #> names=['foo', 123] ``` 1. Note that the validation of the second item is skipped. If it has the wrong type it will emit a warning during serialization. * [`ValidateAs`][pydantic.functional_validators.ValidateAs] can be used to validate an custom type from a type natively supported by Pydantic. This is particularly useful when using custom types with multiple fields. ```python {lint="skip"} from typing import Annotated from pydantic import BaseModel, TypeAdapter, ValidateAs class MyCls: def __init__(self, a: int) -> None: self.a = a def __repr__(self) -> str: return f"MyCls(a={self.a})" class ValModel(BaseModel): a: int ta = TypeAdapter( Annotated[MyCls, ValidateAs(ValModel, lambda v: MyCls(a=v.a))] ) print(ta.validate_python({'a': 1})) #> MyCls(a=1) ``` * [`PydanticUseDefault`][pydantic_core.PydanticUseDefault] can be used to notify Pydantic that the default value should be used. ```python from typing import Annotated, Any from pydantic_core import PydanticUseDefault from pydantic import BaseModel, BeforeValidator def default_if_none(value: Any) -> Any: if value is None: raise PydanticUseDefault() return value class Model(BaseModel): name: Annotated[str, BeforeValidator(default_if_none)] = 'default_name' print(Model(name=None)) #> name='default_name' ``` ## JSON Schema and field validators When using [*before*](#field-before-validator), [*plain*](#field-plain-validator) or [*wrap*](#field-wrap-validator) field validators, the accepted input type may be different from the field annotation. Consider the following example: ```python from typing import Any from pydantic import BaseModel, field_validator class Model(BaseModel): value: str @field_validator('value', mode='before') @classmethod def cast_ints(cls, value: Any) -> Any: if isinstance(value, int): return str(value) else: return value print(Model(value='a')) #> value='a' print(Model(value=1)) #> value='1' ``` While the type hint for `value` is `str`, the `cast_ints` validator also allows integers. To specify the correct input type, the `json_schema_input_type` argument can be provided: ```python from typing import Any, Union from pydantic import BaseModel, field_validator class Model(BaseModel): value: str @field_validator( 'value', mode='before', json_schema_input_type=Union[int, str] ) @classmethod def cast_ints(cls, value: Any) -> Any: if isinstance(value, int): return str(value) else: return value print(Model.model_json_schema()['properties']['value']) #> {'anyOf': [{'type': 'integer'}, {'type': 'string'}], 'title': 'Value'} ``` As a convenience, Pydantic will use the field type if the argument is not provided (unless you are using a [*plain*](#field-plain-validator) validator, in which case `json_schema_input_type` defaults to [`Any`][typing.Any] as the field type is completely discarded). pydantic-pydantic-ba0aa01/docs/contributing.md000066400000000000000000000276531517143232300216040ustar00rootroot00000000000000We'd love you to contribute to Pydantic! ## Issues Questions, feature requests and bug reports are all welcome as [discussions or issues](https://github.com/pydantic/pydantic/issues/new/choose). **However, to report a security vulnerability, please see our [security policy](https://github.com/pydantic/pydantic/security/policy).** To make it as simple as possible for us to help you, please include the output of the following call in your issue: ```bash python -c "import pydantic.version; print(pydantic.version.version_info())" ``` If you're using Pydantic prior to **v2.0** please use: ```bash python -c "import pydantic.utils; print(pydantic.utils.version_info())" ``` Please try to always include the above unless you're unable to install Pydantic or **know** it's not relevant to your question or feature request. ## Pull Requests It should be extremely simple to get started and create a Pull Request. Pydantic is released regularly so you should see your improvements release in a matter of days or weeks 🚀. Unless your change is trivial (typo, docs tweak etc.), please create an issue to discuss the change before creating a pull request. !!! note "Pydantic V1 is in maintenance mode" Pydantic v1 is in maintenance mode, meaning that only bug fixes and security fixes will be accepted. New features should be targeted at Pydantic v2. To submit a fix to Pydantic v1, use the `1.10.X-fixes` as a target branch. If you're looking for something to get your teeth into, check out the ["help wanted"](https://github.com/pydantic/pydantic/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) label on github. To make contributing as easy and fast as possible, you'll want to run tests and linting locally. Luckily, Pydantic has few dependencies, doesn't require compiling and tests don't need access to databases, etc. Because of this, setting up and running the tests should be very simple. !!! tip **tl;dr**: use `make format` to fix formatting, `make` to run tests and linting and `make docs` to build the docs. ### Prerequisites You'll need the following prerequisites: * Any Python version between **Python 3.9 and 3.12** * [**uv**](https://docs.astral.sh/uv/getting-started/installation/) or other virtual environment tool * [**git**](https://git-scm.com/) - For version control * [**make**](https://www.gnu.org/software/make/) - For running development commands (or use `nmake` on Windows) * [**Rust**](https://rustup.rs/) - Rust stable (or nightly for coverage) ### Installation and setup Fork the repository on GitHub and clone your fork locally. ```bash # Clone your fork and cd into the repo directory git clone git@github.com:/pydantic.git cd pydantic # Install UV and pre-commit # We use pipx here, for other options see: # https://docs.astral.sh/uv/getting-started/installation/ # https://pre-commit.com/#install # To get pipx itself: # https://pypa.github.io/pipx/ pipx install uv pipx install pre-commit # Install pydantic, dependencies, test dependencies and doc dependencies make install ``` ### Check out a new branch and make your changes Create a new branch for your changes. ```bash # Checkout a new branch and make your changes git switch -c my-new-feature-branch # Make your changes... ``` ### Run tests and linting Run tests and linting locally to make sure everything is working as expected. ```bash # Run automated code formatting and linting make format # Pydantic uses ruff, an awesome Python linter written in rust # https://github.com/astral-sh/ruff # Run tests and linting make # There are a few sub-commands in Makefile like `test`, `testcov` and `lint` # which you might want to use, but generally just `make` should be all you need. # You can run `make help` to see more options. ``` ### Build documentation If you've made any changes to the documentation (including changes to function signatures, class definitions, or docstrings that will appear in the API documentation), make sure it builds successfully. We use `mkdocs-material[imaging]` to support social previews (see the [plugin documentation](https://squidfunk.github.io/mkdocs-material/plugins/requirements/image-processing/)). ```bash # Build documentation make docs # If you have changed the documentation, make sure it builds successfully. # You can also use `uv run mkdocs serve` to serve the documentation at localhost:8000 ``` If this isn't working due to issues with the imaging plugin, try commenting out the `social` plugin line in `mkdocs.yml` and running `make docs` again. #### Updating the documentation We push a new version of the documentation with each minor release, and we push to a `dev` path with each commit to `main`. If you're updating the documentation out of cycle with a minor release and want your changes to be reflected on `latest`, do the following: 1. Open a PR against `main` with your docs changes 2. Once the PR is merged, checkout the `docs-update` branch. This branch should be up to date with the latest patch release. For example, if the latest release is `v2.9.2`, you should make sure `docs-update` is up to date with the `v2.9.2` tag. 3. Checkout a new branch from `docs-update` and cherry-pick your changes onto this branch. 4. Push your changes and open a PR against `docs-update`. 5. Once the PR is merged, the new docs will be built and deployed. !!! note Maintainer shortcut - as a maintainer, you can skip the second PR and just cherry pick directly onto the `docs-update` branch. ### Commit and push your changes Commit your changes, push your branch to GitHub, and create a pull request. Please follow the pull request template and fill in as much information as possible. Link to any relevant issues and include a description of your changes. When your pull request is ready for review, add a comment with the message "please review" and we'll take a look as soon as we can. ## Documentation style Documentation is written in Markdown and built using [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/). API documentation is built from docstrings using [mkdocstrings](https://mkdocstrings.github.io/). ### Code documentation When contributing to Pydantic, please make sure that all code is well documented. The following should be documented using properly formatted docstrings: * Modules * Class definitions * Function definitions * Module-level variables Pydantic uses [Google-style docstrings](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings) formatted according to [PEP 257](https://www.python.org/dev/peps/pep-0257/) guidelines. (See [Example Google Style Python Docstrings](https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html) for further examples.) [pydocstyle](https://www.pydocstyle.org/en/stable/index.html) is used for linting docstrings. You can run `make format` to check your docstrings. Where this is a conflict between Google-style docstrings and pydocstyle linting, follow the pydocstyle linting hints. Class attributes and function arguments should be documented in the format "name: description." When applicable, a return type should be documented with just a description. Types are inferred from the signature. ```python class Foo: """A class docstring. Attributes: bar: A description of bar. Defaults to "bar". """ bar: str = 'bar' ``` ```python def bar(self, baz: int) -> str: """A function docstring. Args: baz: A description of `baz`. Returns: A description of the return value. """ return 'bar' ``` You may include example code in docstrings. This code should be complete, self-contained, and runnable. Docstring examples are tested, so make sure they are correct and complete. See [`BeforeValidator`][pydantic.functional_validators.AfterValidator] for an example. !!! note "Class and instance attributes" Class attributes should be documented in the class docstring. Instance attributes should be documented as "Args" in the `__init__` docstring. ### Documentation Style In general, documentation should be written in a friendly, approachable style. It should be easy to read and understand, and should be as concise as possible while still being complete. Code examples are encouraged, but should be kept short and simple. However, every code example should be complete, self-contained, and runnable. (If you're not sure how to do this, ask for help!) We prefer print output to naked asserts, but if you're testing something that doesn't have a useful print output, asserts are fine. Pydantic's unit test will test all code examples in the documentation, so it's important that they are correct and complete. When adding a new code example, use the following to test examples and update their formatting and output: ```bash # Run tests and update code examples pytest tests/test_docs.py --update-examples ``` ## Debugging Python and Rust If you're working with `pydantic` and `pydantic-core`, you might find it helpful to debug Python and Rust code together. Here's a quick guide on how to do that. This tutorial is done in VSCode, but you can use similar steps in other IDEs.
## Badges [![Pydantic v1](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/pydantic/pydantic/main/docs/badge/v1.json)](https://pydantic.dev) [![Pydantic v2](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/pydantic/pydantic/main/docs/badge/v2.json)](https://pydantic.dev) Pydantic has a badge that you can use to show that your project uses Pydantic. You can use this badge in your `README.md`: ### With Markdown ```md [![Pydantic v1](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/pydantic/pydantic/main/docs/badge/v1.json)](https://pydantic.dev) [![Pydantic v2](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/pydantic/pydantic/main/docs/badge/v2.json)](https://pydantic.dev) ``` ### With reStructuredText ```rst .. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/pydantic/pydantic/main/docs/badge/v1.json :target: https://pydantic.dev :alt: Pydantic .. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/pydantic/pydantic/main/docs/badge/v2.json :target: https://pydantic.dev :alt: Pydantic ``` ### With HTML ```html Pydantic Version 1 Pydantic Version 2 ``` ## Adding your library as part of Pydantic's third party test suite To be able to identify regressions early during development, Pydantic runs tests on various third-party projects using Pydantic. We consider adding support for testing new open source projects (that rely heavily on Pydantic) if your said project matches some of the following criteria: * The project is actively maintained. * The project makes use of Pydantic internals (e.g. relying on the [`BaseModel`][pydantic.BaseModel] metaclass, typing utilities). * The project is popular enough (although small projects can still be included depending on how Pydantic is being used). * The project CI is simple enough to be ported into Pydantic's testing workflow. If your project meets some of these criteria, you can [open feature request][open feature request] to discuss the inclusion of your project. [open feature request]: https://github.com/pydantic/pydantic/issues/new?assignees=&labels=feature+request&projects=&template=feature_request.yml pydantic-pydantic-ba0aa01/docs/errors/000077500000000000000000000000001517143232300200525ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/docs/errors/errors.md000066400000000000000000000237231517143232300217170ustar00rootroot00000000000000 Pydantic will raise a [`ValidationError`][pydantic_core.ValidationError] whenever it finds an error in the data it's validating. !!! note Validation code should not raise the [`ValidationError`][pydantic_core.ValidationError] itself, but rather raise a [`ValueError`][] or a [`AssertionError`][] (or subclass thereof) which will be caught and used to populate the final [`ValidationError`][pydantic_core.ValidationError]. For more details, refer to the [dedicated section](../concepts/validators.md#raising-validation-errors) of the validators documentation. That [`ValidationError`][pydantic_core.ValidationError] will contain information about all the errors and how they happened. You can access these errors in several ways: | Method | Description | |--------------------------------------------------------------|------------------------------------------------------------------------------------------------| | [`errors()`][pydantic_core.ValidationError.errors] | Returns a list of [`ErrorDetails`][pydantic_core.ErrorDetails] errors found in the input data. | | [`error_count()`][pydantic_core.ValidationError.error_count] | Returns the number of errors. | | [`json()`][pydantic_core.ValidationError.json] | Returns a JSON representation of the list errors. | | `str(e)` | Returns a human-readable representation of the errors. | The [`ErrorDetails`][pydantic_core.ErrorDetails] object is a dictionary. It contains the following: | Property | Description | |---------------------------------------------|--------------------------------------------------------------------------------| | [`ctx`][pydantic_core.ErrorDetails.ctx] | An optional object which contains values required to render the error message. | | [`input`][pydantic_core.ErrorDetails.input] | The input provided for validation. | | [`loc`][pydantic_core.ErrorDetails.loc] | The error's location as a list. | | [`msg`][pydantic_core.ErrorDetails.msg] | A human-readable explanation of the error. | | [`type`][pydantic_core.ErrorDetails.type] | A computer-readable identifier of the error type. | | [`url`][pydantic_core.ErrorDetails.url] | The documentation URL giving information about the error. | The first item in the [`loc`][pydantic_core.ErrorDetails.loc] list will be the field where the error occurred, and if the field is a [sub-model](../concepts/models.md#nested-models), subsequent items will be present to indicate the nested location of the error. As a demonstration: ```python from pydantic import BaseModel, Field, ValidationError, field_validator class Location(BaseModel): lat: float = 0.1 lng: float = 10.1 class Model(BaseModel): is_required: float gt_int: int = Field(gt=42) list_of_ints: list[int] a_float: float recursive_model: Location @field_validator('a_float', mode='after') @classmethod def validate_float(cls, value: float) -> float: if value > 2.0: raise ValueError('Invalid float value') return value data = { 'list_of_ints': ['1', 2, 'bad'], 'a_float': 3.0, 'recursive_model': {'lat': 4.2, 'lng': 'New York'}, 'gt_int': 21, } try: Model(**data) except ValidationError as e: print(e) """ 5 validation errors for Model is_required Field required [type=missing, input_value={'list_of_ints': ['1', 2,...ew York'}, 'gt_int': 21}, input_type=dict] gt_int Input should be greater than 42 [type=greater_than, input_value=21, input_type=int] list_of_ints.2 Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='bad', input_type=str] a_float Value error, Invalid float value [type=value_error, input_value=3.0, input_type=float] recursive_model.lng Input should be a valid number, unable to parse string as a number [type=float_parsing, input_value='New York', input_type=str] """ try: Model(**data) except ValidationError as e: print(e.errors()) """ [ { 'type': 'missing', 'loc': ('is_required',), 'msg': 'Field required', 'input': { 'list_of_ints': ['1', 2, 'bad'], 'a_float': 3.0, 'recursive_model': {'lat': 4.2, 'lng': 'New York'}, 'gt_int': 21, }, 'url': 'https://errors.pydantic.dev/2/v/missing', }, { 'type': 'greater_than', 'loc': ('gt_int',), 'msg': 'Input should be greater than 42', 'input': 21, 'ctx': {'gt': 42}, 'url': 'https://errors.pydantic.dev/2/v/greater_than', }, { 'type': 'int_parsing', 'loc': ('list_of_ints', 2), 'msg': 'Input should be a valid integer, unable to parse string as an integer', 'input': 'bad', 'url': 'https://errors.pydantic.dev/2/v/int_parsing', }, { 'type': 'value_error', 'loc': ('a_float',), 'msg': 'Value error, Invalid float value', 'input': 3.0, 'ctx': {'error': ValueError('Invalid float value')}, 'url': 'https://errors.pydantic.dev/2/v/value_error', }, { 'type': 'float_parsing', 'loc': ('recursive_model', 'lng'), 'msg': 'Input should be a valid number, unable to parse string as a number', 'input': 'New York', 'url': 'https://errors.pydantic.dev/2/v/float_parsing', }, ] """ ``` ## Error messages Pydantic attempts to provide useful default error messages for validation and usage errors, which can be found here: * [Validation Errors](validation_errors.md): Errors that happen during data validation. * [Usage Errors](usage_errors.md): Errors that happen when using Pydantic. ### Customize error messages You can customize error messages by creating a custom error handler. ```python from pydantic_core import ErrorDetails from pydantic import BaseModel, HttpUrl, ValidationError CUSTOM_MESSAGES = { 'int_parsing': 'This is not an integer! 🤦', 'url_scheme': 'Hey, use the right URL scheme! I wanted {expected_schemes}.', } def convert_errors( e: ValidationError, custom_messages: dict[str, str] ) -> list[ErrorDetails]: new_errors: list[ErrorDetails] = [] for error in e.errors(): custom_message = custom_messages.get(error['type']) if custom_message: ctx = error.get('ctx') error['msg'] = ( custom_message.format(**ctx) if ctx else custom_message ) new_errors.append(error) return new_errors class Model(BaseModel): a: int b: HttpUrl try: Model(a='wrong', b='ftp://example.com') except ValidationError as e: errors = convert_errors(e, CUSTOM_MESSAGES) print(errors) """ [ { 'type': 'int_parsing', 'loc': ('a',), 'msg': 'This is not an integer! 🤦', 'input': 'wrong', 'url': 'https://errors.pydantic.dev/2/v/int_parsing', }, { 'type': 'url_scheme', 'loc': ('b',), 'msg': "Hey, use the right URL scheme! I wanted 'http' or 'https'.", 'input': 'ftp://example.com', 'ctx': {'expected_schemes': "'http' or 'https'"}, 'url': 'https://errors.pydantic.dev/2/v/url_scheme', }, ] """ ``` A common use case would be to translate error messages. For example, in the above example, we could translate the error messages replacing the `CUSTOM_MESSAGES` dictionary with a dictionary of translations. Another example is customizing the way that the `'loc'` value of an error is represented. ```python from typing import Any, Union from pydantic import BaseModel, ValidationError def loc_to_dot_sep(loc: tuple[Union[str, int], ...]) -> str: path = '' for i, x in enumerate(loc): if isinstance(x, str): if i > 0: path += '.' path += x elif isinstance(x, int): path += f'[{x}]' else: raise TypeError('Unexpected type') return path def convert_errors(e: ValidationError) -> list[dict[str, Any]]: new_errors: list[dict[str, Any]] = e.errors() for error in new_errors: error['loc'] = loc_to_dot_sep(error['loc']) return new_errors class TestNestedModel(BaseModel): key: str value: str class TestModel(BaseModel): items: list[TestNestedModel] data = {'items': [{'key': 'foo', 'value': 'bar'}, {'key': 'baz'}]} try: TestModel.model_validate(data) except ValidationError as e: print(e.errors()) # (1)! """ [ { 'type': 'missing', 'loc': ('items', 1, 'value'), 'msg': 'Field required', 'input': {'key': 'baz'}, 'url': 'https://errors.pydantic.dev/2/v/missing', } ] """ pretty_errors = convert_errors(e) print(pretty_errors) # (2)! """ [ { 'type': 'missing', 'loc': 'items[1].value', 'msg': 'Field required', 'input': {'key': 'baz'}, 'url': 'https://errors.pydantic.dev/2/v/missing', } ] """ ``` 1. By default, `e.errors()` produces a list of errors with `loc` values that take the form of tuples. 2. With our custom `loc_to_dot_sep` function, we've modified the form of the `loc` representation. pydantic-pydantic-ba0aa01/docs/errors/usage_errors.md000066400000000000000000001051461517143232300231030ustar00rootroot00000000000000Pydantic attempts to provide useful errors. The following sections provide details on common errors developers may encounter when working with Pydantic, along with suggestions for addressing the error condition. ## Class not fully defined {#class-not-fully-defined} This error is raised when a type referenced in an annotation of a pydantic-validated type (such as a subclass of `BaseModel`, or a pydantic `dataclass`) is not defined: ```python from typing import ForwardRef from pydantic import BaseModel, PydanticUserError UndefinedType = ForwardRef('UndefinedType') class Foobar(BaseModel): a: UndefinedType try: Foobar(a=1) except PydanticUserError as exc_info: assert exc_info.code == 'class-not-fully-defined' ``` Or when the type has been defined after usage: ```python from typing import Optional from pydantic import BaseModel, PydanticUserError class Foo(BaseModel): a: Optional['Bar'] = None try: # this doesn't work, see raised error foo = Foo(a={'b': {'a': None}}) except PydanticUserError as exc_info: assert exc_info.code == 'class-not-fully-defined' class Bar(BaseModel): b: 'Foo' # this works, though foo = Foo(a={'b': {'a': None}}) ``` For BaseModel subclasses, it can be fixed by defining the type and then calling `.model_rebuild()`: ```python from typing import Optional from pydantic import BaseModel class Foo(BaseModel): a: Optional['Bar'] = None class Bar(BaseModel): b: 'Foo' Foo.model_rebuild() foo = Foo(a={'b': {'a': None}}) ``` In other cases, the error message should indicate how to rebuild the class with the appropriate type defined. ## Custom JSON Schema {#custom-json-schema} The `__modify_schema__` method is no longer supported in V2. You should use the `__get_pydantic_json_schema__` method instead. The `__modify_schema__` used to receive a single argument representing the JSON schema. See the example below: ```python {title="Old way"} from pydantic import BaseModel, PydanticUserError try: class Model(BaseModel): @classmethod def __modify_schema__(cls, field_schema): field_schema.update(examples=['example']) except PydanticUserError as exc_info: assert exc_info.code == 'custom-json-schema' ``` The new method `__get_pydantic_json_schema__` receives two arguments: the first is a dictionary denoted as `CoreSchema`, and the second a callable `handler` that receives a `CoreSchema` as parameter, and returns a JSON schema. See the example below: ```python {title="New way"} from typing import Any from pydantic_core import CoreSchema from pydantic import BaseModel, GetJsonSchemaHandler class Model(BaseModel): @classmethod def __get_pydantic_json_schema__( cls, core_schema: CoreSchema, handler: GetJsonSchemaHandler ) -> dict[str, Any]: json_schema = super().__get_pydantic_json_schema__(core_schema, handler) json_schema = handler.resolve_ref_schema(json_schema) json_schema.update(examples=['example']) return json_schema print(Model.model_json_schema()) """ {'examples': ['example'], 'properties': {}, 'title': 'Model', 'type': 'object'} """ ``` ## Invalid decorator fields {#decorator-invalid-fields} This error is raised when the field names provided to the [`@field_validator`][pydantic.field_validator] or [`@field_serializer`][pydantic.field_serializer] decorators are not strings. ```python from pydantic import BaseModel, PydanticUserError, field_validator try: class Model(BaseModel): a: str b: str @field_validator(['a', 'b']) @classmethod def check_fields(cls, v): return v except PydanticUserError as exc_info: assert exc_info.code == 'decorator-invalid-fields' ``` Fields should be provided as separate string arguments: ```python from pydantic import BaseModel, field_validator class Model(BaseModel): a: str b: str @field_validator('a', 'b') @classmethod def check_fields(cls, v): return v ``` ## Decorator with no fields {#decorator-missing-arguments} This error is raised when the [`@field_validator`][pydantic.field_validator] or [`@field_serializer`][pydantic.field_serializer] decorators are used bare, without any arguments. ```python from pydantic import BaseModel, PydanticUserError, field_validator try: class Model(BaseModel): a: str @field_validator @classmethod def checker(cls, v): return v except PydanticUserError as exc_info: assert exc_info.code == 'decorator-missing-arguments' ``` At least one field name (and optionally other field names and keyword arguments) should be provided. ```python from pydantic import BaseModel, field_validator class Model(BaseModel): a: str @field_validator('a') @classmethod def checker(cls, v): return v ``` ## Decorator on missing field {#decorator-missing-field} This error is raised when you define a decorator with a field that is not valid. ```python from typing import Any from pydantic import BaseModel, PydanticUserError, field_validator try: class Model(BaseModel): a: str @field_validator('b') def check_b(cls, v: Any): return v except PydanticUserError as exc_info: assert exc_info.code == 'decorator-missing-field' ``` You can use `check_fields=False` if you're inheriting from the model and intended this. ```python from typing import Any from pydantic import BaseModel, create_model, field_validator class Model(BaseModel): @field_validator('a', check_fields=False) def check_a(cls, v: Any): return v model = create_model('FooModel', a=(str, 'cake'), __base__=Model) ``` ## Discriminator no field {#discriminator-no-field} This error is raised when a model in discriminated unions doesn't define a discriminator field. ```python from typing import Literal, Union from pydantic import BaseModel, Field, PydanticUserError class Cat(BaseModel): c: str class Dog(BaseModel): pet_type: Literal['dog'] d: str try: class Model(BaseModel): pet: Union[Cat, Dog] = Field(discriminator='pet_type') number: int except PydanticUserError as exc_info: assert exc_info.code == 'discriminator-no-field' ``` ## Discriminator alias type {#discriminator-alias-type} This error is raised when you define a non-string alias on a discriminator field. ```python from typing import Literal, Union from pydantic import AliasChoices, BaseModel, Field, PydanticUserError class Cat(BaseModel): pet_type: Literal['cat'] = Field( validation_alias=AliasChoices('Pet', 'PET') ) c: str class Dog(BaseModel): pet_type: Literal['dog'] d: str try: class Model(BaseModel): pet: Union[Cat, Dog] = Field(discriminator='pet_type') number: int except PydanticUserError as exc_info: assert exc_info.code == 'discriminator-alias-type' ``` ## Discriminator needs literal {#discriminator-needs-literal} This error is raised when you define a non-`Literal` type on a discriminator field. ```python from typing import Literal, Union from pydantic import BaseModel, Field, PydanticUserError class Cat(BaseModel): pet_type: int c: str class Dog(BaseModel): pet_type: Literal['dog'] d: str try: class Model(BaseModel): pet: Union[Cat, Dog] = Field(discriminator='pet_type') number: int except PydanticUserError as exc_info: assert exc_info.code == 'discriminator-needs-literal' ``` ## Discriminator alias {#discriminator-alias} This error is raised when you define different aliases on discriminator fields. ```python from typing import Literal, Union from pydantic import BaseModel, Field, PydanticUserError class Cat(BaseModel): pet_type: Literal['cat'] = Field(validation_alias='PET') c: str class Dog(BaseModel): pet_type: Literal['dog'] = Field(validation_alias='Pet') d: str try: class Model(BaseModel): pet: Union[Cat, Dog] = Field(discriminator='pet_type') number: int except PydanticUserError as exc_info: assert exc_info.code == 'discriminator-alias' ``` ## Invalid discriminator validator {#discriminator-validator} This error is raised when you use a before, wrap, or plain validator on a discriminator field. This is disallowed because the discriminator field is used to determine the type of the model to use for validation, so you can't use a validator that might change its value. ```python from typing import Literal, Union from pydantic import BaseModel, Field, PydanticUserError, field_validator class Cat(BaseModel): pet_type: Literal['cat'] @field_validator('pet_type', mode='before') @classmethod def validate_pet_type(cls, v): if v == 'kitten': return 'cat' return v class Dog(BaseModel): pet_type: Literal['dog'] try: class Model(BaseModel): pet: Union[Cat, Dog] = Field(discriminator='pet_type') number: int except PydanticUserError as exc_info: assert exc_info.code == 'discriminator-validator' ``` This can be worked around by using a standard `Union`, dropping the discriminator: ```python from typing import Literal, Union from pydantic import BaseModel, field_validator class Cat(BaseModel): pet_type: Literal['cat'] @field_validator('pet_type', mode='before') @classmethod def validate_pet_type(cls, v): if v == 'kitten': return 'cat' return v class Dog(BaseModel): pet_type: Literal['dog'] class Model(BaseModel): pet: Union[Cat, Dog] assert Model(pet={'pet_type': 'kitten'}).pet.pet_type == 'cat' ``` ## Callable discriminator case with no tag {#callable-discriminator-no-tag} This error is raised when a `Union` that uses a callable `Discriminator` doesn't have `Tag` annotations for all cases. ```python from typing import Annotated, Union from pydantic import BaseModel, Discriminator, PydanticUserError, Tag def model_x_discriminator(v): if isinstance(v, str): return 'str' if isinstance(v, (dict, BaseModel)): return 'model' # tag missing for both union choices try: class DiscriminatedModel(BaseModel): x: Annotated[ Union[str, 'DiscriminatedModel'], Discriminator(model_x_discriminator), ] except PydanticUserError as exc_info: assert exc_info.code == 'callable-discriminator-no-tag' # tag missing for `'DiscriminatedModel'` union choice try: class DiscriminatedModel(BaseModel): x: Annotated[ Union[Annotated[str, Tag('str')], 'DiscriminatedModel'], Discriminator(model_x_discriminator), ] except PydanticUserError as exc_info: assert exc_info.code == 'callable-discriminator-no-tag' # tag missing for `str` union choice try: class DiscriminatedModel(BaseModel): x: Annotated[ Union[str, Annotated['DiscriminatedModel', Tag('model')]], Discriminator(model_x_discriminator), ] except PydanticUserError as exc_info: assert exc_info.code == 'callable-discriminator-no-tag' ``` ## `TypedDict` version {#typed-dict-version} This error is raised when you use [typing.TypedDict][] instead of `typing_extensions.TypedDict` on Python < 3.12. ## Model parent field overridden {#model-field-overridden} This error is raised when a field defined on a base class was overridden by a non-annotated attribute. ```python from pydantic import BaseModel, PydanticUserError class Foo(BaseModel): a: float try: class Bar(Foo): x: float = 12.3 a = 123.0 except PydanticUserError as exc_info: assert exc_info.code == 'model-field-overridden' ``` ## Model field missing annotation {#model-field-missing-annotation} This error is raised when a field doesn't have an annotation. ```python from pydantic import BaseModel, Field, PydanticUserError try: class Model(BaseModel): a = Field('foobar') b = None except PydanticUserError as exc_info: assert exc_info.code == 'model-field-missing-annotation' ``` If the field is not meant to be a field, you may be able to resolve the error by annotating it as a `ClassVar`: ```python from typing import ClassVar from pydantic import BaseModel class Model(BaseModel): a: ClassVar[str] ``` Or updating `model_config['ignored_types']`: ```python from pydantic import BaseModel, ConfigDict class IgnoredType: pass class MyModel(BaseModel): model_config = ConfigDict(ignored_types=(IgnoredType,)) _a = IgnoredType() _b: int = IgnoredType() _c: IgnoredType _d: IgnoredType = IgnoredType() ``` ## `Config` and `model_config` both defined {#config-both} This error is raised when `class Config` and `model_config` are used together. ```python from pydantic import BaseModel, ConfigDict, PydanticUserError try: class Model(BaseModel): model_config = ConfigDict(from_attributes=True) a: str class Config: from_attributes = True except PydanticUserError as exc_info: assert exc_info.code == 'config-both' ``` ## Keyword arguments removed {#removed-kwargs} This error is raised when the keyword arguments are not available in Pydantic V2. For example, `regex` is removed from Pydantic V2: ```python from pydantic import BaseModel, Field, PydanticUserError try: class Model(BaseModel): x: str = Field(regex='test') except PydanticUserError as exc_info: assert exc_info.code == 'removed-kwargs' ``` ## Circular reference schema {#circular-reference-schema} This error is raised when a circular reference is found that would otherwise result in an infinite recursion. For example, this is a valid type alias: ```python {test="skip" lint="skip" upgrade="skip"} type A = list[A] | None ``` while these are not: ```python {test="skip" lint="skip" upgrade="skip"} type A = A type B = C type C = B ``` ## JSON schema invalid type {#invalid-for-json-schema} This error is raised when Pydantic fails to generate a JSON schema for some `CoreSchema`. ```python from pydantic import BaseModel, ImportString, PydanticUserError class Model(BaseModel): a: ImportString try: Model.model_json_schema() except PydanticUserError as exc_info: assert exc_info.code == 'invalid-for-json-schema' ``` ## JSON schema already used {#json-schema-already-used} This error is raised when the JSON schema generator has already been used to generate a JSON schema. You must create a new instance to generate a new JSON schema. ## BaseModel instantiated {#base-model-instantiated} This error is raised when you instantiate `BaseModel` directly. Pydantic models should inherit from `BaseModel`. ```python from pydantic import BaseModel, PydanticUserError try: BaseModel() except PydanticUserError as exc_info: assert exc_info.code == 'base-model-instantiated' ``` ## Undefined annotation {#undefined-annotation} This error is raised when handling undefined annotations during `CoreSchema` generation. ```python from pydantic import BaseModel, PydanticUndefinedAnnotation class Model(BaseModel): a: 'B' # noqa F821 try: Model.model_rebuild() except PydanticUndefinedAnnotation as exc_info: assert exc_info.code == 'undefined-annotation' ``` ## Schema for unknown type {#schema-for-unknown-type} This error is raised when Pydantic fails to generate a `CoreSchema` for some type. ```python from pydantic import BaseModel, PydanticUserError try: class Model(BaseModel): x: 43 = 123 except PydanticUserError as exc_info: assert exc_info.code == 'schema-for-unknown-type' ``` ## Import error {#import-error} This error is raised when you try to import an object that was available in Pydantic V1, but has been removed in Pydantic V2. See the [Migration Guide](../migration.md) for more information. ## `create_model` field definitions {#create-model-field-definitions} This error is raised when you provide invalid field definitions in [`create_model()`][pydantic.create_model]. ```python from pydantic import PydanticUserError, create_model try: create_model('FooModel', foo=(str, 'default value', 'more')) except PydanticUserError as exc_info: assert exc_info.code == 'create-model-field-definitions' ``` The fields definition syntax can be found in the [dynamic model creation](../concepts/models.md#dynamic-model-creation) documentation. ## Validator on instance method {#validator-instance-method} This error is raised when you apply a validator on an instance method. ```python from pydantic import BaseModel, PydanticUserError, field_validator try: class Model(BaseModel): a: int = 1 @field_validator('a') def check_a(self, value): return value except PydanticUserError as exc_info: assert exc_info.code == 'validator-instance-method' ``` ## `json_schema_input_type` used with the wrong mode {#validator-input-type} This error is raised when you explicitly specify a value for the `json_schema_input_type` argument and `mode` isn't set to either `'before'`, `'plain'` or `'wrap'`. ```python from pydantic import BaseModel, PydanticUserError, field_validator try: class Model(BaseModel): a: int = 1 @field_validator('a', mode='after', json_schema_input_type=int) @classmethod def check_a(self, value): return value except PydanticUserError as exc_info: assert exc_info.code == 'validator-input-type' ``` Documenting the JSON Schema input type is only possible for validators where the given value can be anything. That is why it isn't available for `after` validators, where the value is first validated against the type annotation. ## Root validator, `pre`, `skip_on_failure` {#root-validator-pre-skip} If you use `@root_validator` with `pre=False` (the default) you MUST specify `skip_on_failure=True`. The `skip_on_failure=False` option is no longer available. If you were not trying to set `skip_on_failure=False`, you can safely set `skip_on_failure=True`. If you do, this root validator will no longer be called if validation fails for any of the fields. Please see the [Migration Guide](../migration.md) for more details. ## `model_serializer` instance methods {#model-serializer-instance-method} `@model_serializer` must be applied to instance methods. This error is raised when you apply `model_serializer` on an instance method without `self`: ```python from pydantic import BaseModel, PydanticUserError, model_serializer try: class MyModel(BaseModel): a: int @model_serializer def _serialize(slf, x, y, z): return slf except PydanticUserError as exc_info: assert exc_info.code == 'model-serializer-instance-method' ``` Or on a class method: ```python from pydantic import BaseModel, PydanticUserError, model_serializer try: class MyModel(BaseModel): a: int @model_serializer @classmethod def _serialize(self, x, y, z): return self except PydanticUserError as exc_info: assert exc_info.code == 'model-serializer-instance-method' ``` ## `validator`, `field`, `config`, and `info` {#validator-field-config-info} The `field` and `config` parameters are not available in Pydantic V2. Please use the `info` parameter instead. You can access the configuration via `info.config`, but it is a dictionary instead of an object like it was in Pydantic V1. The `field` argument is no longer available. ## Pydantic V1 validator signature {#validator-v1-signature} This error is raised when you use an unsupported signature for Pydantic V1-style validator. ```python import warnings from pydantic import BaseModel, PydanticUserError, validator warnings.filterwarnings('ignore', category=DeprecationWarning) try: class Model(BaseModel): a: int @validator('a') def check_a(cls, value, foo): return value except PydanticUserError as exc_info: assert exc_info.code == 'validator-v1-signature' ``` ## Unrecognized `field_validator` signature {#validator-signature} This error is raised when a `field_validator` or `model_validator` function has the wrong signature. ```python from pydantic import BaseModel, PydanticUserError, field_validator try: class Model(BaseModel): a: str @field_validator('a') @classmethod def check_a(cls): return 'a' except PydanticUserError as exc_info: assert exc_info.code == 'validator-signature' ``` ## Unrecognized `field_serializer` signature {#field-serializer-signature} This error is raised when the `field_serializer` function has the wrong signature. ```python from pydantic import BaseModel, PydanticUserError, field_serializer try: class Model(BaseModel): x: int @field_serializer('x') def no_args(): return 'x' except PydanticUserError as exc_info: assert exc_info.code == 'field-serializer-signature' ``` Valid field serializer signatures are: ```python {test="skip" lint="skip" upgrade="skip"} from pydantic import FieldSerializationInfo, SerializerFunctionWrapHandler, field_serializer # an instance method with the default mode or `mode='plain'` @field_serializer('x') # or @field_serializer('x', mode='plain') def ser_x(self, value: Any, info: FieldSerializationInfo): ... # a static method or function with the default mode or `mode='plain'` @field_serializer('x') # or @field_serializer('x', mode='plain') @staticmethod def ser_x(value: Any, info: FieldSerializationInfo): ... # equivalent to def ser_x(value: Any, info: FieldSerializationInfo): ... serializer('x')(ser_x) # an instance method with `mode='wrap'` @field_serializer('x', mode='wrap') def ser_x(self, value: Any, nxt: SerializerFunctionWrapHandler, info: FieldSerializationInfo): ... # a static method or function with `mode='wrap'` @field_serializer('x', mode='wrap') @staticmethod def ser_x(value: Any, nxt: SerializerFunctionWrapHandler, info: FieldSerializationInfo): ... # equivalent to def ser_x(value: Any, nxt: SerializerFunctionWrapHandler, info: FieldSerializationInfo): ... serializer('x')(ser_x) # For all of these, you can also choose to omit the `info` argument, for example: @field_serializer('x') def ser_x(self, value: Any): ... @field_serializer('x', mode='wrap') def ser_x(self, value: Any, handler: SerializerFunctionWrapHandler): ... ``` ## Unrecognized `model_serializer` signature {#model-serializer-signature} This error is raised when the `model_serializer` function has the wrong signature. ```python from pydantic import BaseModel, PydanticUserError, model_serializer try: class MyModel(BaseModel): a: int @model_serializer def _serialize(self, x, y, z): return self except PydanticUserError as exc_info: assert exc_info.code == 'model-serializer-signature' ``` Valid model serializer signatures are: ```python {test="skip" lint="skip" upgrade="skip"} from pydantic import SerializerFunctionWrapHandler, SerializationInfo, model_serializer # an instance method with the default mode or `mode='plain'` @model_serializer # or model_serializer(mode='plain') def mod_ser(self, info: SerializationInfo): ... # an instance method with `mode='wrap'` @model_serializer(mode='wrap') def mod_ser(self, handler: SerializerFunctionWrapHandler, info: SerializationInfo): # For all of these, you can also choose to omit the `info` argument, for example: @model_serializer(mode='plain') def mod_ser(self): ... @model_serializer(mode='wrap') def mod_ser(self, handler: SerializerFunctionWrapHandler): ... ``` ## Multiple field serializers {#multiple-field-serializers} This error is raised when multiple `model_serializer` functions are defined for a field. ```python from pydantic import BaseModel, PydanticUserError, field_serializer try: class MyModel(BaseModel): x: int y: int @field_serializer('x', 'y') def serializer1(v): return f'{v:,}' @field_serializer('x') def serializer2(v): return v except PydanticUserError as exc_info: assert exc_info.code == 'multiple-field-serializers' ``` ## Invalid annotated type {#invalid-annotated-type} This error is raised when an annotation cannot annotate a type. ```python from typing import Annotated from pydantic import BaseModel, FutureDate, PydanticUserError try: class Model(BaseModel): foo: Annotated[str, FutureDate()] except PydanticUserError as exc_info: assert exc_info.code == 'invalid-annotated-type' ``` ## `config` is unused with `TypeAdapter` {#type-adapter-config-unused} You will get this error if you try to pass `config` to `TypeAdapter` when the type is a type that has its own config that cannot be overridden (currently this is only `BaseModel`, `TypedDict` and `dataclass`): ```python from typing_extensions import TypedDict from pydantic import ConfigDict, PydanticUserError, TypeAdapter class MyTypedDict(TypedDict): x: int try: TypeAdapter(MyTypedDict, config=ConfigDict(strict=True)) except PydanticUserError as exc_info: assert exc_info.code == 'type-adapter-config-unused' ``` Instead you'll need to subclass the type and override or set the config on it: ```python from typing_extensions import TypedDict from pydantic import ConfigDict, TypeAdapter class MyTypedDict(TypedDict): x: int # or `model_config = ...` for BaseModel __pydantic_config__ = ConfigDict(strict=True) TypeAdapter(MyTypedDict) # ok ``` ## Cannot specify `model_config['extra']` with `RootModel` {#root-model-extra} Because `RootModel` is not capable of storing or even accepting extra fields during initialization, we raise an error if you try to specify a value for the config setting `'extra'` when creating a subclass of `RootModel`: ```python from pydantic import PydanticUserError, RootModel try: class MyRootModel(RootModel): model_config = {'extra': 'allow'} root: int except PydanticUserError as exc_info: assert exc_info.code == 'root-model-extra' ``` ## Cannot evaluate type annotation {#unevaluable-type-annotation} Because type annotations are evaluated *after* assignments, you might get unexpected results when using a type annotation name that clashes with one of your fields. We raise an error in the following case: ```python {test="skip"} from datetime import date from pydantic import BaseModel, Field class Model(BaseModel): date: date = Field(description='A date') ``` As a workaround, you can either use an alias or change your import: ```python {lint="skip"} import datetime # Or `from datetime import date as _date` from pydantic import BaseModel, Field class Model(BaseModel): date: datetime.date = Field(description='A date') ``` ## Incompatible `dataclass` `init` and `extra` settings {#dataclass-init-false-extra-allow} Pydantic does not allow the specification of the `extra='allow'` setting on a dataclass while any of the fields have `init=False` set. Thus, you may not do something like the following: ```python {test="skip"} from pydantic import ConfigDict, Field from pydantic.dataclasses import dataclass @dataclass(config=ConfigDict(extra='allow')) class A: a: int = Field(init=False, default=1) ``` The above snippet results in the following error during schema building for the `A` dataclass: ```output pydantic.errors.PydanticUserError: Field a has `init=False` and dataclass has config setting `extra="allow"`. This combination is not allowed. ``` ## Incompatible `init` and `init_var` settings on `dataclass` field {#clashing-init-and-init-var} The `init=False` and `init_var=True` settings are mutually exclusive. Doing so results in the `PydanticUserError` shown in the example below. ```python {test="skip"} from pydantic import Field from pydantic.dataclasses import dataclass @dataclass class Foo: bar: str = Field(init=False, init_var=True) """ pydantic.errors.PydanticUserError: Dataclass field bar has init=False and init_var=True, but these are mutually exclusive. """ ``` ## `model_config` is used as a model field {#model-config-invalid-field-name} This error is raised when `model_config` is used as the name of a field. ```python from pydantic import BaseModel, PydanticUserError try: class Model(BaseModel): model_config: str except PydanticUserError as exc_info: assert exc_info.code == 'model-config-invalid-field-name' ``` ## [`with_config`][pydantic.config.with_config] is used on a `BaseModel` subclass {#with-config-on-model} This error is raised when the [`with_config`][pydantic.config.with_config] decorator is used on a class which is already a Pydantic model (use the `model_config` attribute instead). ```python from pydantic import BaseModel, PydanticUserError, with_config try: @with_config({'allow_inf_nan': True}) class Model(BaseModel): bar: str except PydanticUserError as exc_info: assert exc_info.code == 'with-config-on-model' ``` ## `dataclass` is used on a `BaseModel` subclass {#dataclass-on-model} This error is raised when the Pydantic `dataclass` decorator is used on a class which is already a Pydantic model. ```python from pydantic import BaseModel, PydanticUserError from pydantic.dataclasses import dataclass try: @dataclass class Model(BaseModel): bar: str except PydanticUserError as exc_info: assert exc_info.code == 'dataclass-on-model' ``` ## Unsupported type for `validate_call` {#validate-call-type} `validate_call` has some limitations on the callables it can validate. This error is raised when you try to use it with an unsupported callable. Currently the supported callables are functions (including lambdas, but not built-ins) and methods and instances of [`partial`][functools.partial]. In the case of [`partial`][functools.partial], the function being partially applied must be one of the supported callables. ### `@classmethod`, `@staticmethod`, and `@property` These decorators must be put before `validate_call`. ```python from pydantic import PydanticUserError, validate_call # error try: class A: @validate_call @classmethod def f1(cls): ... except PydanticUserError as exc_info: assert exc_info.code == 'validate-call-type' # correct @classmethod @validate_call def f2(cls): ... ``` ### Classes While classes are callables themselves, `validate_call` can't be applied on them, as it needs to know about which method to use (`__init__` or `__new__`) to fetch type annotations. If you want to validate the constructor of a class, you should put `validate_call` on top of the appropriate method instead. ```python from pydantic import PydanticUserError, validate_call # error try: @validate_call class A1: ... except PydanticUserError as exc_info: assert exc_info.code == 'validate-call-type' # correct class A2: @validate_call def __init__(self): ... @validate_call def __new__(cls): ... ``` ### Callable instances Although instances can be callable by implementing a `__call__` method, currently the instances of these types cannot be validated with `validate_call`. This may change in the future, but for now, you should use `validate_call` explicitly on `__call__` instead. ```python from pydantic import PydanticUserError, validate_call # error try: class A1: def __call__(self): ... validate_call(A1()) except PydanticUserError as exc_info: assert exc_info.code == 'validate-call-type' # correct class A2: @validate_call def __call__(self): ... ``` ### Invalid signature This is generally less common, but a possible reason is that you are trying to validate a method that doesn't have at least one argument (usually `self`). ```python from pydantic import PydanticUserError, validate_call try: class A: def f(): ... validate_call(A().f) except PydanticUserError as exc_info: assert exc_info.code == 'validate-call-type' ``` ## [`Unpack`][typing.Unpack] used without a [`TypedDict`][typing.TypedDict] {#unpack-typed-dict} This error is raised when [`Unpack`][typing.Unpack] is used with something other than a [`TypedDict`][typing.TypedDict] class object to type hint variadic keyword parameters. For reference, see the [related specification section] and [PEP 692]. ```python from typing_extensions import Unpack from pydantic import PydanticUserError, validate_call try: @validate_call def func(**kwargs: Unpack[int]): pass except PydanticUserError as exc_info: assert exc_info.code == 'unpack-typed-dict' ``` ## Overlapping unpacked [`TypedDict`][typing.TypedDict] fields and arguments {#overlapping-unpack-typed-dict} This error is raised when the typed dictionary used to type hint variadic keywords parameters has field names overlapping with other parameters (unless [positional only][positional-only_parameter]). For reference, see the [related specification section] and [PEP 692]. ```python from typing_extensions import TypedDict, Unpack from pydantic import PydanticUserError, validate_call class TD(TypedDict): a: int try: @validate_call def func(a: int, **kwargs: Unpack[TD]): pass except PydanticUserError as exc_info: assert exc_info.code == 'overlapping-unpack-typed-dict' ``` [related specification section]: https://typing.readthedocs.io/en/latest/spec/callables.html#unpack-for-keyword-arguments [PEP 692]: https://peps.python.org/pep-0692/ ## Invalid `Self` type {#invalid-self-type} Currently, [`Self`][typing.Self] can only be used to annotate a field of a class (specifically, subclasses of [`BaseModel`][pydantic.BaseModel], [`NamedTuple`][typing.NamedTuple], [`TypedDict`][typing.TypedDict], or dataclasses). Attempting to use [`Self`][typing.Self] in any other ways will raise this error. ```python from typing_extensions import Self from pydantic import PydanticUserError, validate_call try: @validate_call def func(self: Self): pass except PydanticUserError as exc_info: assert exc_info.code == 'invalid-self-type' ``` The following example of [`validate_call()`][pydantic.validate_call] will also raise this error, even though it is correct from a type-checking perspective. This may be supported in the future. ```python from typing_extensions import Self from pydantic import BaseModel, PydanticUserError, validate_call try: class A(BaseModel): @validate_call def func(self, arg: Self): pass except PydanticUserError as exc_info: assert exc_info.code == 'invalid-self-type' ``` ## `validate_by_alias` and `validate_by_name` both set to `False` {#validate-by-alias-and-name-false} This error is raised when you set `validate_by_alias` and `validate_by_name` to `False` in the configuration. This is not allowed because it would make it impossible to populate attributes. ```python from pydantic import BaseModel, ConfigDict, Field, PydanticUserError try: class Model(BaseModel): a: int = Field(alias='A') model_config = ConfigDict( validate_by_alias=False, validate_by_name=False ) except PydanticUserError as exc_info: assert exc_info.code == 'validate-by-alias-and-name-false' ``` pydantic-pydantic-ba0aa01/docs/errors/validation_errors.md000066400000000000000000001304161517143232300241270ustar00rootroot00000000000000Pydantic attempts to provide useful validation errors. Below are details on common validation errors users may encounter when working with pydantic, together with some suggestions on how to fix them. ## `arguments_type` This error is raised when an object that would be passed as arguments to a function during validation is not a `tuple`, `list`, or `dict`. Because `NamedTuple` uses function calls in its implementation, that is one way to produce this error: ```python from typing import NamedTuple from pydantic import BaseModel, ValidationError class MyNamedTuple(NamedTuple): x: int class MyModel(BaseModel): field: MyNamedTuple try: MyModel.model_validate({'field': 'invalid'}) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'arguments_type' ``` ## `assertion_error` This error is raised when a failing `assert` statement is encountered during validation: ```python from pydantic import BaseModel, ValidationError, field_validator class Model(BaseModel): x: int @field_validator('x') @classmethod def force_x_positive(cls, v): assert v > 0 return v try: Model(x=-1) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'assertion_error' ``` ## `bool_parsing` This error is raised when the input value is a string that is not valid for coercion to a boolean: ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): x: bool Model(x='true') # OK try: Model(x='test') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'bool_parsing' ``` ## `bool_type` This error is raised when the input value's type is not valid for a `bool` field: ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): x: bool try: Model(x=None) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'bool_type' ``` This error is also raised for strict fields when the input value is not an instance of `bool`. ## `bytes_invalid_encoding` This error is raised when a `bytes` value is invalid under the configured encoding. In the following example, `'a'` is invalid hex (odd number of digits). ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): x: bytes model_config = {'val_json_bytes': 'hex'} try: Model(x='a') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'bytes_invalid_encoding' ``` ## `bytes_too_long` This error is raised when the length of a `bytes` value is greater than the field's `max_length` constraint: ```python from pydantic import BaseModel, Field, ValidationError class Model(BaseModel): x: bytes = Field(max_length=3) try: Model(x=b'test') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'bytes_too_long' ``` ## `bytes_too_short` This error is raised when the length of a `bytes` value is less than the field's `min_length` constraint: ```python from pydantic import BaseModel, Field, ValidationError class Model(BaseModel): x: bytes = Field(min_length=3) try: Model(x=b't') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'bytes_too_short' ``` ## `bytes_type` This error is raised when the input value's type is not valid for a `bytes` field: ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): x: bytes try: Model(x=123) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'bytes_type' ``` This error is also raised for strict fields when the input value is not an instance of `bytes`. ## `callable_type` This error is raised when the input value is not valid as a `Callable`: ```python from typing import Any, Callable from pydantic import BaseModel, ImportString, ValidationError class Model(BaseModel): x: ImportString[Callable[[Any], Any]] Model(x='math:cos') # OK try: Model(x='os.path') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'callable_type' ``` ## `complex_str_parsing` This error is raised when the input value is a string but cannot be parsed as a complex number because it does not follow the [rule](https://docs.python.org/3/library/functions.html#complex) in Python: ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): num: complex try: # Complex numbers in json are expected to be valid complex strings. # This value `abc` is not a valid complex string. Model.model_validate_json('{"num": "abc"}') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'complex_str_parsing' ``` ## `complex_type` This error is raised when the input value cannot be interpreted as a complex number: ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): num: complex try: Model(num=False) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'complex_type' ``` ## `dataclass_exact_type` This error is raised when validating a dataclass with `strict=True` and the input is not an instance of the dataclass: ```python import pydantic.dataclasses from pydantic import TypeAdapter, ValidationError @pydantic.dataclasses.dataclass class MyDataclass: x: str adapter = TypeAdapter(MyDataclass) print(adapter.validate_python(MyDataclass(x='test'), strict=True)) #> MyDataclass(x='test') print(adapter.validate_python({'x': 'test'})) #> MyDataclass(x='test') try: adapter.validate_python({'x': 'test'}, strict=True) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'dataclass_exact_type' ``` ## `dataclass_type` This error is raised when the input value is not valid for a `dataclass` field: ```python from pydantic import ValidationError, dataclasses @dataclasses.dataclass class Inner: x: int @dataclasses.dataclass class Outer: y: Inner Outer(y=Inner(x=1)) # OK try: Outer(y=1) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'dataclass_type' ``` ## `date_from_datetime_inexact` This error is raised when the input `datetime` value provided for a `date` field has a nonzero time component. For a timestamp to parse into a field of type `date`, the time components must all be zero: ```python from datetime import date, datetime from pydantic import BaseModel, ValidationError class Model(BaseModel): x: date Model(x='2023-01-01') # OK Model(x=datetime(2023, 1, 1)) # OK try: Model(x=datetime(2023, 1, 1, 12)) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'date_from_datetime_inexact' ``` ## `date_from_datetime_parsing` This error is raised when the input value is a string that cannot be parsed for a `date` field: ```python from datetime import date from pydantic import BaseModel, ValidationError class Model(BaseModel): x: date try: Model(x='XX1494012000') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'date_from_datetime_parsing' ``` ## `date_future` This error is raised when the input value provided for a `FutureDate` field is not in the future: ```python from datetime import date from pydantic import BaseModel, FutureDate, ValidationError class Model(BaseModel): x: FutureDate try: Model(x=date(2000, 1, 1)) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'date_future' ``` ## `date_parsing` This error is raised when validating JSON where the input value is string that cannot be parsed for a `date` field: ```python import json from datetime import date from pydantic import BaseModel, Field, ValidationError class Model(BaseModel): x: date = Field(strict=True) try: Model.model_validate_json(json.dumps({'x': '1'})) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'date_parsing' ``` ## `date_past` This error is raised when the value provided for a `PastDate` field is not in the past: ```python from datetime import date, timedelta from pydantic import BaseModel, PastDate, ValidationError class Model(BaseModel): x: PastDate try: Model(x=date.today() + timedelta(1)) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'date_past' ``` ## `date_type` This error is raised when the input value's type is not valid for a `date` field: ```python from datetime import date from pydantic import BaseModel, ValidationError class Model(BaseModel): x: date try: Model(x=None) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'date_type' ``` This error is also raised for strict fields when the input value is not an instance of `date`. ## `datetime_from_date_parsing` This error is raised when the input value is a string that cannot be parsed for a `datetime` field: ```python from datetime import datetime from pydantic import BaseModel, ValidationError class Model(BaseModel): x: datetime try: # there is no 13th month Model(x='2023-13-01') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'datetime_from_date_parsing' ``` ## `datetime_future` This error is raised when the value provided for a `FutureDatetime` field is not in the future: ```python from datetime import datetime from pydantic import BaseModel, FutureDatetime, ValidationError class Model(BaseModel): x: FutureDatetime try: Model(x=datetime(2000, 1, 1)) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'datetime_future' ``` ## `datetime_object_invalid` This error is raised when something about the `datetime` object is not valid: ```python from datetime import datetime, tzinfo from pydantic import AwareDatetime, BaseModel, ValidationError class CustomTz(tzinfo): # utcoffset is not implemented! def tzname(self, _dt): return 'CustomTZ' class Model(BaseModel): x: AwareDatetime try: Model(x=datetime(2023, 1, 1, tzinfo=CustomTz())) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'datetime_object_invalid' ``` ## `datetime_parsing` This error is raised when the value is a string that cannot be parsed for a `datetime` field: ```python import json from datetime import datetime from pydantic import BaseModel, Field, ValidationError class Model(BaseModel): x: datetime = Field(strict=True) try: Model.model_validate_json(json.dumps({'x': 'not a datetime'})) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'datetime_parsing' ``` ## `datetime_past` This error is raised when the value provided for a `PastDatetime` field is not in the past: ```python from datetime import datetime, timedelta from pydantic import BaseModel, PastDatetime, ValidationError class Model(BaseModel): x: PastDatetime try: Model(x=datetime.now() + timedelta(100)) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'datetime_past' ``` ## `datetime_type` This error is raised when the input value's type is not valid for a `datetime` field: ```python from datetime import datetime from pydantic import BaseModel, ValidationError class Model(BaseModel): x: datetime try: Model(x=None) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'datetime_type' ``` This error is also raised for strict fields when the input value is not an instance of `datetime`. ## `decimal_max_digits` This error is raised when the value provided for a `Decimal` has too many digits: ```python from decimal import Decimal from pydantic import BaseModel, Field, ValidationError class Model(BaseModel): x: Decimal = Field(max_digits=3) try: Model(x='42.1234') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'decimal_max_digits' ``` ## `decimal_max_places` This error is raised when the value provided for a `Decimal` has too many digits after the decimal point: ```python from decimal import Decimal from pydantic import BaseModel, Field, ValidationError class Model(BaseModel): x: Decimal = Field(decimal_places=3) try: Model(x='42.1234') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'decimal_max_places' ``` ## `decimal_parsing` This error is raised when the value provided for a `Decimal` could not be parsed as a decimal number: ```python from decimal import Decimal from pydantic import BaseModel, Field, ValidationError class Model(BaseModel): x: Decimal = Field(decimal_places=3) try: Model(x='test') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'decimal_parsing' ``` ## `decimal_type` This error is raised when the value provided for a `Decimal` is of the wrong type: ```python from decimal import Decimal from pydantic import BaseModel, Field, ValidationError class Model(BaseModel): x: Decimal = Field(decimal_places=3) try: Model(x=[1, 2, 3]) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'decimal_type' ``` This error is also raised for strict fields when the input value is not an instance of `Decimal`. ## `decimal_whole_digits` This error is raised when the value provided for a `Decimal` has more digits before the decimal point than `max_digits` - `decimal_places` (as long as both are specified): ```python from decimal import Decimal from pydantic import BaseModel, Field, ValidationError class Model(BaseModel): x: Decimal = Field(max_digits=6, decimal_places=3) try: Model(x='12345.6') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'decimal_whole_digits' ``` ## `default_factory_not_called` This error is raised when a [default factory taking validated data](../concepts/fields.md#default-factory-validated-data) can't be called, because validation failed on previous fields: ```python from pydantic import BaseModel, Field, ValidationError class Model(BaseModel): a: int = Field(gt=10) b: int = Field(default_factory=lambda data: data['a']) try: Model(a=1) except ValidationError as exc: print(exc) """ 2 validation errors for Model a Input should be greater than 10 [type=greater_than, input_value=1, input_type=int] b The default factory uses validated data, but at least one validation error occurred [type=default_factory_not_called] """ print(repr(exc.errors()[1]['type'])) #> 'default_factory_not_called' ``` ## `dict_type` This error is raised when the input value's type is not `dict` for a `dict` field: ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): x: dict try: Model(x=['1', '2']) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'dict_type' ``` ## `enum` This error is raised when the input value does not exist in an `enum` field members: ```python from enum import Enum from pydantic import BaseModel, ValidationError class MyEnum(str, Enum): option = 'option' class Model(BaseModel): x: MyEnum try: Model(x='other_option') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'enum' ``` ## `extra_forbidden` This error is raised when the input value contains extra fields, but `model_config['extra'] == 'forbid'`: ```python from pydantic import BaseModel, ConfigDict, ValidationError class Model(BaseModel): x: str model_config = ConfigDict(extra='forbid') try: Model(x='test', y='test') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'extra_forbidden' ``` You can read more about the `extra` configuration in the [Extra Attributes][pydantic.config.ConfigDict.extra] section. ## `finite_number` This error is raised when the value is infinite, or too large to be represented as a 64-bit floating point number during validation: ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): x: int try: Model(x=2.2250738585072011e308) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'finite_number' ``` ## `float_parsing` This error is raised when the value is a string that can't be parsed as a `float`: ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): x: float try: Model(x='test') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'float_parsing' ``` ## `float_type` This error is raised when the input value's type is not valid for a `float` field: ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): x: float try: Model(x=None) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'float_type' ``` ## `frozen_field` This error is raised when you attempt to assign a value to a field with `frozen=True`, or to delete such a field: ```python from pydantic import BaseModel, Field, ValidationError class Model(BaseModel): x: str = Field('test', frozen=True) model = Model() try: model.x = 'test1' except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'frozen_field' try: del model.x except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'frozen_field' ``` ## `frozen_instance` This error is raised when `frozen` is set in the [configuration](../concepts/config.md) and you attempt to delete or assign a new value to any of the fields: ```python from pydantic import BaseModel, ConfigDict, ValidationError class Model(BaseModel): x: int model_config = ConfigDict(frozen=True) m = Model(x=1) try: m.x = 2 except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'frozen_instance' try: del m.x except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'frozen_instance' ``` ## `frozen_set_type` This error is raised when the input value's type is not valid for a `frozenset` field: ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): x: frozenset try: model = Model(x='test') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'frozen_set_type' ``` ## `get_attribute_error` This error is raised when `model_config['from_attributes'] == True` and an error is raised while reading the attributes: ```python from pydantic import BaseModel, ConfigDict, ValidationError class Foobar: def __init__(self): self.x = 1 @property def y(self): raise RuntimeError('intentional error') class Model(BaseModel): x: int y: str model_config = ConfigDict(from_attributes=True) try: Model.model_validate(Foobar()) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'get_attribute_error' ``` ## `greater_than` This error is raised when the value is not greater than the field's `gt` constraint: ```python from pydantic import BaseModel, Field, ValidationError class Model(BaseModel): x: int = Field(gt=10) try: Model(x=10) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'greater_than' ``` ## `greater_than_equal` This error is raised when the value is not greater than or equal to the field's `ge` constraint: ```python from pydantic import BaseModel, Field, ValidationError class Model(BaseModel): x: int = Field(ge=10) try: Model(x=9) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'greater_than_equal' ``` ## `int_from_float` This error is raised when you provide a `float` value for an `int` field: ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): x: int try: Model(x=0.5) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'int_from_float' ``` ## `int_parsing` This error is raised when the value can't be parsed as `int`: ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): x: int try: Model(x='test') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'int_parsing' ``` ## `int_parsing_size` This error is raised when attempting to parse a python or JSON value from a string outside the maximum range that Python `str` to `int` parsing permits: ```python import json from pydantic import BaseModel, ValidationError class Model(BaseModel): x: int # from Python assert Model(x='1' * 4_300).x == int('1' * 4_300) # OK too_long = '1' * 4_301 try: Model(x=too_long) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'int_parsing_size' # from JSON try: Model.model_validate_json(json.dumps({'x': too_long})) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'int_parsing_size' ``` ## `int_type` This error is raised when the input value's type is not valid for an `int` field: ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): x: int try: Model(x=None) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'int_type' ``` ## `invalid_key` This error is raised when attempting to validate a `dict` that has a key that is not an instance of `str`: ```python from pydantic import BaseModel, ConfigDict, ValidationError class Model(BaseModel): x: int model_config = ConfigDict(extra='allow') try: Model.model_validate({'x': 1, b'y': 2}) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'invalid_key' ``` ## `is_instance_of` This error is raised when the input value is not an instance of the expected type: ```python from pydantic import BaseModel, ConfigDict, ValidationError class Nested: x: str class Model(BaseModel): y: Nested model_config = ConfigDict(arbitrary_types_allowed=True) try: Model(y='test') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'is_instance_of' ``` ## `is_subclass_of` This error is raised when the input value is not a subclass of the expected type: ```python from pydantic import BaseModel, ValidationError class Nested: x: str class Model(BaseModel): y: type[Nested] try: Model(y='test') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'is_subclass_of' ``` ## `iterable_type` This error is raised when the input value is not valid as an `Iterable`: ```python from collections.abc import Iterable from pydantic import BaseModel, ValidationError class Model(BaseModel): y: Iterable[str] try: Model(y=123) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'iterable_type' ``` ## `iteration_error` This error is raised when an error occurs during iteration: ```python from pydantic import BaseModel, ValidationError def gen(): yield 1 raise RuntimeError('error') class Model(BaseModel): x: list[int] try: Model(x=gen()) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'iteration_error' ``` ## `json_invalid` This error is raised when the input value is not a valid JSON string: ```python from pydantic import BaseModel, Json, ValidationError class Model(BaseModel): x: Json try: Model(x='test') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'json_invalid' ``` ## `json_type` This error is raised when the input value is of a type that cannot be parsed as JSON: ```python from pydantic import BaseModel, Json, ValidationError class Model(BaseModel): x: Json try: Model(x=None) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'json_type' ``` ## `less_than` This error is raised when the input value is not less than the field's `lt` constraint: ```python from pydantic import BaseModel, Field, ValidationError class Model(BaseModel): x: int = Field(lt=10) try: Model(x=10) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'less_than' ``` ## `less_than_equal` This error is raised when the input value is not less than or equal to the field's `le` constraint: ```python from pydantic import BaseModel, Field, ValidationError class Model(BaseModel): x: int = Field(le=10) try: Model(x=11) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'less_than_equal' ``` ## `list_type` This error is raised when the input value's type is not valid for a `list` field: ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): x: list[int] try: Model(x=1) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'list_type' ``` ## `literal_error` This error is raised when the input value is not one of the expected literal values: ```python from typing import Literal from pydantic import BaseModel, ValidationError class Model(BaseModel): x: Literal['a', 'b'] Model(x='a') # OK try: Model(x='c') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'literal_error' ``` ## `mapping_type` This error is raised when a problem occurs during validation due to a failure in a call to the methods from the `Mapping` protocol, such as `.items()`: ```python from collections.abc import Mapping from pydantic import BaseModel, ValidationError class BadMapping(Mapping): def items(self): raise ValueError() def __iter__(self): raise ValueError() def __getitem__(self, key): raise ValueError() def __len__(self): return 1 class Model(BaseModel): x: dict[str, str] try: Model(x=BadMapping()) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'mapping_type' ``` ## `missing` This error is raised when there are required fields missing from the input value: ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): x: str try: Model() except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'missing' ``` ## `missing_argument` This error is raised when a required positional-or-keyword argument is not passed to a function decorated with `validate_call`: ```python from pydantic import ValidationError, validate_call @validate_call def foo(a: int): return a try: foo() except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'missing_argument' ``` ## `missing_keyword_only_argument` This error is raised when a required keyword-only argument is not passed to a function decorated with `validate_call`: ```python from pydantic import ValidationError, validate_call @validate_call def foo(*, a: int): return a try: foo() except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'missing_keyword_only_argument' ``` ## `missing_positional_only_argument` This error is raised when a required positional-only argument is not passed to a function decorated with `validate_call`: ```python from pydantic import ValidationError, validate_call @validate_call def foo(a: int, /): return a try: foo() except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'missing_positional_only_argument' ``` ## `missing_sentinel_error` This error is raised when the experimental `MISSING` sentinel is the only value allowed, and wasn't provided during validation: ```python from pydantic import BaseModel, ValidationError from pydantic.experimental.missing_sentinel import MISSING class Model(BaseModel): f: MISSING try: Model(f=1) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'missing_sentinel_error' ``` ## `model_attributes_type` This error is raised when the input value is not a valid dictionary, model instance, or instance that fields can be extracted from: ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): a: int b: int # simply validating a dict print(Model.model_validate({'a': 1, 'b': 2})) #> a=1 b=2 class CustomObj: def __init__(self, a, b): self.a = a self.b = b # using from attributes to extract fields from an objects print(Model.model_validate(CustomObj(3, 4), from_attributes=True)) #> a=3 b=4 try: Model.model_validate('not an object', from_attributes=True) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'model_attributes_type' ``` ## `model_type` This error is raised when the input to a model is not an instance of the model or dict: ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): a: int b: int # simply validating a dict m = Model.model_validate({'a': 1, 'b': 2}) print(m) #> a=1 b=2 # validating an existing model instance print(Model.model_validate(m)) #> a=1 b=2 try: Model.model_validate('not an object') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'model_type' ``` ## `multiple_argument_values` This error is raised when you provide multiple values for a single argument while calling a function decorated with `validate_call`: ```python from pydantic import ValidationError, validate_call @validate_call def foo(a: int): return a try: foo(1, a=2) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'multiple_argument_values' ``` ## `multiple_of` This error is raised when the input is not a multiple of a field's `multiple_of` constraint: ```python from pydantic import BaseModel, Field, ValidationError class Model(BaseModel): x: int = Field(multiple_of=5) try: Model(x=1) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'multiple_of' ``` ## `needs_python_object` This type of error is raised when validation is attempted from a format that cannot be converted to a Python object. For example, we cannot check `isinstance` or `issubclass` from JSON: ```python import json from pydantic import BaseModel, ValidationError class Model(BaseModel): bm: type[BaseModel] try: Model.model_validate_json(json.dumps({'bm': 'not a basemodel class'})) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'needs_python_object' ``` ## `no_such_attribute` This error is raised when `validate_assignment=True` in the config, and you attempt to assign a value to an attribute that is not an existing field: ```python from pydantic import ConfigDict, ValidationError, dataclasses @dataclasses.dataclass(config=ConfigDict(validate_assignment=True)) class MyDataclass: x: int m = MyDataclass(x=1) try: m.y = 10 except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'no_such_attribute' ``` ## `none_required` This error is raised when the input value is not `None` for a field that requires `None`: ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): x: None try: Model(x=1) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'none_required' ``` !!! note You may encounter this error when there is a naming collision in your model between a field name and its type. More specifically, this error is likely to be thrown when the default value of that field is `None`. For example, the following would yield the `none_required` validation error since the field `int` is set to a default value of `None` and has the exact same name as its type, which causes problems with validation. ```python {test="skip"} from typing import Optional from pydantic import BaseModel class M1(BaseModel): int: Optional[int] = None m = M1(int=123) # errors ``` ## `recursion_loop` This error is raised when a cyclic reference is detected: ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): x: list['Model'] d = {'x': []} d['x'].append(d) try: Model(**d) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'recursion_loop' ``` ## `set_item_not_hashable` This error is raised when an unhashable value is validated against a [`set`][] or a [`frozenset`][]: ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): x: set[object] class Unhashable: __hash__ = None try: Model(x=[{'a': 'b'}, Unhashable()]) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'set_item_not_hashable' print(repr(exc.errors()[1]['type'])) #> 'set_item_not_hashable' ``` ## `set_type` This error is raised when the value type is not valid for a `set` field: ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): x: set[int] try: Model(x='test') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'set_type' ``` ## `string_not_ascii` This error is raised when the input string contains non-ASCII characters: ```python from typing import Annotated from pydantic import BaseModel, StringConstraints, ValidationError class Model(BaseModel): v: Annotated[str, StringConstraints(ascii_only=True)] try: Model(v='caf\u00e9') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'string_not_ascii' ``` ## `string_pattern_mismatch` This error is raised when the input value doesn't match the field's `pattern` constraint: ```python from pydantic import BaseModel, Field, ValidationError class Model(BaseModel): x: str = Field(pattern='test') try: Model(x='1') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'string_pattern_mismatch' ``` ## `string_sub_type` This error is raised when the value is an instance of a strict subtype of `str` when the field is strict: ```python from enum import Enum from pydantic import BaseModel, Field, ValidationError class MyEnum(str, Enum): foo = 'foo' class Model(BaseModel): x: str = Field(strict=True) try: Model(x=MyEnum.foo) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'string_sub_type' ``` ## `string_too_long` This error is raised when the input value is a string whose length is greater than the field's `max_length` constraint: ```python from pydantic import BaseModel, Field, ValidationError class Model(BaseModel): x: str = Field(max_length=3) try: Model(x='test') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'string_too_long' ``` ## `string_too_short` This error is raised when the input value is a string whose length is less than the field's `min_length` constraint: ```python from pydantic import BaseModel, Field, ValidationError class Model(BaseModel): x: str = Field(min_length=3) try: Model(x='t') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'string_too_short' ``` ## `string_type` This error is raised when the input value's type is not valid for a `str` field: ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): x: str try: Model(x=1) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'string_type' ``` This error is also raised for strict fields when the input value is not an instance of `str`. ## `string_unicode` This error is raised when the value cannot be parsed as a Unicode string: ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): x: str try: Model(x=b'\x81') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'string_unicode' ``` ## `time_delta_parsing` This error is raised when the input value is a string that cannot be parsed for a `timedelta` field: ```python from datetime import timedelta from pydantic import BaseModel, ValidationError class Model(BaseModel): x: timedelta try: Model(x='t') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'time_delta_parsing' ``` ## `time_delta_type` This error is raised when the input value's type is not valid for a `timedelta` field: ```python from datetime import timedelta from pydantic import BaseModel, ValidationError class Model(BaseModel): x: timedelta try: Model(x=None) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'time_delta_type' ``` This error is also raised for strict fields when the input value is not an instance of `timedelta`. ## `time_parsing` This error is raised when the input value is a string that cannot be parsed for a `time` field: ```python from datetime import time from pydantic import BaseModel, ValidationError class Model(BaseModel): x: time try: Model(x='25:20:30.400') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'time_parsing' ``` ## `time_type` This error is raised when the value type is not valid for a `time` field: ```python from datetime import time from pydantic import BaseModel, ValidationError class Model(BaseModel): x: time try: Model(x=None) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'time_type' ``` This error is also raised for strict fields when the input value is not an instance of `time`. ## `timezone_aware` This error is raised when the `datetime` value provided for a timezone-aware `datetime` field doesn't have timezone information: ```python from datetime import datetime from pydantic import AwareDatetime, BaseModel, ValidationError class Model(BaseModel): x: AwareDatetime try: Model(x=datetime.now()) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'timezone_aware' ``` ## `timezone_naive` This error is raised when the `datetime` value provided for a timezone-naive `datetime` field has timezone info: ```python from datetime import datetime, timezone from pydantic import BaseModel, NaiveDatetime, ValidationError class Model(BaseModel): x: NaiveDatetime try: Model(x=datetime.now(tz=timezone.utc)) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'timezone_naive' ``` ## `too_long` This error is raised when the input value's length is greater than the field's `max_length` constraint: ```python from pydantic import BaseModel, Field, ValidationError class Model(BaseModel): x: list[int] = Field(max_length=3) try: Model(x=[1, 2, 3, 4]) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'too_long' ``` ## `too_short` This error is raised when the value length is less than the field's `min_length` constraint: ```python from pydantic import BaseModel, Field, ValidationError class Model(BaseModel): x: list[int] = Field(min_length=3) try: Model(x=[1, 2]) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'too_short' ``` ## `tuple_type` This error is raised when the input value's type is not valid for a `tuple` field: ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): x: tuple[int] try: Model(x=None) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'tuple_type' ``` This error is also raised for strict fields when the input value is not an instance of `tuple`. ## `unexpected_keyword_argument` This error is raised when you provide a value by keyword for a positional-only argument while calling a function decorated with `validate_call`: ```python from pydantic import ValidationError, validate_call @validate_call def foo(a: int, /): return a try: foo(a=2) except ValidationError as exc: print(repr(exc.errors()[1]['type'])) #> 'unexpected_keyword_argument' ``` It is also raised when using pydantic.dataclasses and `extra=forbid`: ```python from pydantic import TypeAdapter, ValidationError from pydantic.dataclasses import dataclass @dataclass(config={'extra': 'forbid'}) class Foo: bar: int try: TypeAdapter(Foo).validate_python({'bar': 1, 'foobar': 2}) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'unexpected_keyword_argument' ``` ## `unexpected_positional_argument` This error is raised when you provide a positional value for a keyword-only argument while calling a function decorated with `validate_call`: ```python from pydantic import ValidationError, validate_call @validate_call def foo(*, a: int): return a try: foo(2) except ValidationError as exc: print(repr(exc.errors()[1]['type'])) #> 'unexpected_positional_argument' ``` ## `union_tag_invalid` This error is raised when the input's discriminator is not one of the expected values: ```python from typing import Literal, Union from pydantic import BaseModel, Field, ValidationError class BlackCat(BaseModel): pet_type: Literal['blackcat'] class WhiteCat(BaseModel): pet_type: Literal['whitecat'] class Model(BaseModel): cat: Union[BlackCat, WhiteCat] = Field(discriminator='pet_type') try: Model(cat={'pet_type': 'dog'}) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'union_tag_invalid' ``` ## `union_tag_not_found` This error is raised when it is not possible to extract a discriminator value from the input: ```python from typing import Literal, Union from pydantic import BaseModel, Field, ValidationError class BlackCat(BaseModel): pet_type: Literal['blackcat'] class WhiteCat(BaseModel): pet_type: Literal['whitecat'] class Model(BaseModel): cat: Union[BlackCat, WhiteCat] = Field(discriminator='pet_type') try: Model(cat={'name': 'blackcat'}) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'union_tag_not_found' ``` ## `url_parsing` This error is raised when the input value cannot be parsed as a URL: ```python from pydantic import AnyUrl, BaseModel, ValidationError class Model(BaseModel): x: AnyUrl try: Model(x='test') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'url_parsing' ``` ## `url_scheme` This error is raised when the URL scheme is not valid for the URL type of the field: ```python from pydantic import BaseModel, HttpUrl, ValidationError class Model(BaseModel): x: HttpUrl try: Model(x='ftp://example.com') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'url_scheme' ``` ## `url_syntax_violation` This error is raised when the URL syntax is not valid: ```python from pydantic import BaseModel, Field, HttpUrl, ValidationError class Model(BaseModel): x: HttpUrl = Field(strict=True) try: Model(x='http:////example.com') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'url_syntax_violation' ``` ## `url_too_long` This error is raised when the URL length is greater than 2083: ```python from pydantic import BaseModel, HttpUrl, ValidationError class Model(BaseModel): x: HttpUrl try: Model(x='x' * 2084) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'url_too_long' ``` ## `url_type` This error is raised when the input value's type is not valid for a URL field: ```python from pydantic import BaseModel, HttpUrl, ValidationError class Model(BaseModel): x: HttpUrl try: Model(x=None) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'url_type' ``` ## `uuid_parsing` This error is raised when the input value's type is not valid for a UUID field: ```python from uuid import UUID from pydantic import BaseModel, ValidationError class Model(BaseModel): u: UUID try: Model(u='12345678-124-1234-1234-567812345678') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'uuid_parsing' ``` ## `uuid_type` This error is raised when the input value's type is not valid instance for a UUID field (str, bytes or UUID): ```python from uuid import UUID from pydantic import BaseModel, ValidationError class Model(BaseModel): u: UUID try: Model(u=1234567812412341234567812345678) except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'uuid_type' ``` ## `uuid_version` This error is raised when the input value's type is not match UUID version: ```python from pydantic import UUID5, BaseModel, ValidationError class Model(BaseModel): u: UUID5 try: Model(u='a6cc5730-2261-11ee-9c43-2eb5a363657c') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'uuid_version' ``` ## `value_error` This error is raised when a `ValueError` is raised during validation: ```python from pydantic import BaseModel, ValidationError, field_validator class Model(BaseModel): x: str @field_validator('x') @classmethod def repeat_b(cls, v): raise ValueError() try: Model(x='test') except ValidationError as exc: print(repr(exc.errors()[0]['type'])) #> 'value_error' ``` pydantic-pydantic-ba0aa01/docs/examples/000077500000000000000000000000001517143232300203545ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/docs/examples/custom_validators.md000066400000000000000000000232241517143232300244430ustar00rootroot00000000000000This page provides example snippets for creating more complex, custom validators in Pydantic. Many of these examples are adapted from Pydantic issues and discussions, and are intended to showcase the flexibility and power of Pydantic's validation system. ## Custom `datetime` Validator via [`Annotated`][typing.Annotated] Metadata In this example, we'll construct a custom validator, attached to an [`Annotated`][typing.Annotated] type, that ensures a [`datetime`][datetime.datetime] object adheres to a given timezone constraint. The custom validator supports string specification of the timezone, and will raise an error if the [`datetime`][datetime.datetime] object does not have the correct timezone. We use `__get_pydantic_core_schema__` in the validator to customize the schema of the annotated type (in this case, [`datetime`][datetime.datetime]), which allows us to add custom validation logic. Notably, we use a `wrap` validator function so that we can perform operations both before and after the default `pydantic` validation of a [`datetime`][datetime.datetime]. ```python import datetime as dt from dataclasses import dataclass from pprint import pprint from typing import Annotated, Any, Callable, Optional import pytz from pydantic_core import CoreSchema, core_schema from pydantic import ( GetCoreSchemaHandler, PydanticUserError, TypeAdapter, ValidationError, ) @dataclass(frozen=True) class MyDatetimeValidator: tz_constraint: Optional[str] = None def tz_constraint_validator( self, value: dt.datetime, handler: Callable, # (1)! ): """Validate tz_constraint and tz_info.""" # handle naive datetimes if self.tz_constraint is None: assert ( value.tzinfo is None ), 'tz_constraint is None, but provided value is tz-aware.' return handler(value) # validate tz_constraint and tz-aware tzinfo if self.tz_constraint not in pytz.all_timezones: raise PydanticUserError( f'Invalid tz_constraint: {self.tz_constraint}', code='unevaluable-type-annotation', ) result = handler(value) # (2)! assert self.tz_constraint == str( result.tzinfo ), f'Invalid tzinfo: {str(result.tzinfo)}, expected: {self.tz_constraint}' return result def __get_pydantic_core_schema__( self, source_type: Any, handler: GetCoreSchemaHandler, ) -> CoreSchema: return core_schema.no_info_wrap_validator_function( self.tz_constraint_validator, handler(source_type), ) LA = 'America/Los_Angeles' ta = TypeAdapter(Annotated[dt.datetime, MyDatetimeValidator(LA)]) print( ta.validate_python(dt.datetime(2023, 1, 1, 0, 0, tzinfo=pytz.timezone(LA))) ) #> 2023-01-01 00:00:00-07:53 LONDON = 'Europe/London' try: ta.validate_python( dt.datetime(2023, 1, 1, 0, 0, tzinfo=pytz.timezone(LONDON)) ) except ValidationError as ve: pprint(ve.errors(), width=100) """ [{'ctx': {'error': AssertionError('Invalid tzinfo: Europe/London, expected: America/Los_Angeles')}, 'input': datetime.datetime(2023, 1, 1, 0, 0, tzinfo=), 'loc': (), 'msg': 'Assertion failed, Invalid tzinfo: Europe/London, expected: America/Los_Angeles', 'type': 'assertion_error', 'url': 'https://errors.pydantic.dev/2.8/v/assertion_error'}] """ ``` 1. The `handler` function is what we call to validate the input with standard `pydantic` validation 2. We call the `handler` function to validate the input with standard `pydantic` validation in this wrap validator We can also enforce UTC offset constraints in a similar way. Assuming we have a `lower_bound` and an `upper_bound`, we can create a custom validator to ensure our `datetime` has a UTC offset that is inclusive within the boundary we define: ```python import datetime as dt from dataclasses import dataclass from pprint import pprint from typing import Annotated, Any, Callable import pytz from pydantic_core import CoreSchema, core_schema from pydantic import GetCoreSchemaHandler, TypeAdapter, ValidationError @dataclass(frozen=True) class MyDatetimeValidator: lower_bound: int upper_bound: int def validate_tz_bounds(self, value: dt.datetime, handler: Callable): """Validate and test bounds""" assert value.utcoffset() is not None, 'UTC offset must exist' assert self.lower_bound <= self.upper_bound, 'Invalid bounds' result = handler(value) hours_offset = value.utcoffset().total_seconds() / 3600 assert ( self.lower_bound <= hours_offset <= self.upper_bound ), 'Value out of bounds' return result def __get_pydantic_core_schema__( self, source_type: Any, handler: GetCoreSchemaHandler, ) -> CoreSchema: return core_schema.no_info_wrap_validator_function( self.validate_tz_bounds, handler(source_type), ) LA = 'America/Los_Angeles' # UTC-7 or UTC-8 ta = TypeAdapter(Annotated[dt.datetime, MyDatetimeValidator(-10, -5)]) print( ta.validate_python(dt.datetime(2023, 1, 1, 0, 0, tzinfo=pytz.timezone(LA))) ) #> 2023-01-01 00:00:00-07:53 LONDON = 'Europe/London' try: print( ta.validate_python( dt.datetime(2023, 1, 1, 0, 0, tzinfo=pytz.timezone(LONDON)) ) ) except ValidationError as e: pprint(e.errors(), width=100) """ [{'ctx': {'error': AssertionError('Value out of bounds')}, 'input': datetime.datetime(2023, 1, 1, 0, 0, tzinfo=), 'loc': (), 'msg': 'Assertion failed, Value out of bounds', 'type': 'assertion_error', 'url': 'https://errors.pydantic.dev/2.8/v/assertion_error'}] """ ``` ## Validating Nested Model Fields Here, we demonstrate two ways to validate a field of a nested model, where the validator utilizes data from the parent model. In this example, we construct a validator that checks that each user's password is not in a list of forbidden passwords specified by the parent model. One way to do this is to place a custom validator on the outer model: ```python from typing_extensions import Self from pydantic import BaseModel, ValidationError, model_validator class User(BaseModel): username: str password: str class Organization(BaseModel): forbidden_passwords: list[str] users: list[User] @model_validator(mode='after') def validate_user_passwords(self) -> Self: """Check that user password is not in forbidden list. Raise a validation error if a forbidden password is encountered.""" for user in self.users: current_pw = user.password if current_pw in self.forbidden_passwords: raise ValueError( f'Password {current_pw} is forbidden. Please choose another password for user {user.username}.' ) return self data = { 'forbidden_passwords': ['123'], 'users': [ {'username': 'Spartacat', 'password': '123'}, {'username': 'Iceburgh', 'password': '87'}, ], } try: org = Organization(**data) except ValidationError as e: print(e) """ 1 validation error for Organization Value error, Password 123 is forbidden. Please choose another password for user Spartacat. [type=value_error, input_value={'forbidden_passwords': [...gh', 'password': '87'}]}, input_type=dict] """ ``` Alternatively, a custom validator can be used in the nested model class (`User`), with the forbidden passwords data from the parent model being passed in via validation context. !!! warning The ability to mutate the context within a validator adds a lot of power to nested validation, but can also lead to confusing or hard-to-debug code. Use this approach at your own risk! ```python from pydantic import BaseModel, ValidationError, ValidationInfo, field_validator class User(BaseModel): username: str password: str @field_validator('password', mode='after') @classmethod def validate_user_passwords( cls, password: str, info: ValidationInfo ) -> str: """Check that user password is not in forbidden list.""" forbidden_passwords = ( info.context.get('forbidden_passwords', []) if info.context else [] ) if password in forbidden_passwords: raise ValueError(f'Password {password} is forbidden.') return password class Organization(BaseModel): forbidden_passwords: list[str] users: list[User] @field_validator('forbidden_passwords', mode='after') @classmethod def add_context(cls, v: list[str], info: ValidationInfo) -> list[str]: if info.context is not None: info.context.update({'forbidden_passwords': v}) return v data = { 'forbidden_passwords': ['123'], 'users': [ {'username': 'Spartacat', 'password': '123'}, {'username': 'Iceburgh', 'password': '87'}, ], } try: org = Organization.model_validate(data, context={}) except ValidationError as e: print(e) """ 1 validation error for Organization users.0.password Value error, Password 123 is forbidden. [type=value_error, input_value='123', input_type=str] """ ``` Note that if the context property is not included in `model_validate`, then `info.context` will be `None` and the forbidden passwords list will not get added to the context in the above implementation. As such, `validate_user_passwords` would not carry out the desired password validation. More details about validation context can be found in the [validators documentation](../concepts/validators.md#validation-context). pydantic-pydantic-ba0aa01/docs/examples/dynamic_models.md000066400000000000000000000172111517143232300236670ustar00rootroot00000000000000Models can be [created dynamically](../concepts/models.md#dynamic-model-creation) using the [`create_model()`][pydantic.create_model] factory function. In this example, we will show how to dynamically derive a model from an existing one, making every field optional. To achieve this, we will make use of the [`model_fields`][pydantic.main.BaseModel.model_fields] model class attribute, and derive new annotations from the field definitions to be passed to the [`create_model()`][pydantic.create_model] factory. Of course, this example can apply to any use case where you need to derive a new model from another (remove default values, add aliases, etc). === "Python 3.9" ```python {lint="skip" linenums="1"} from typing import Annotated, Union from pydantic import BaseModel, Field, create_model def make_fields_optional(model_cls: type[BaseModel]) -> type[BaseModel]: new_fields = {} for f_name, f_info in model_cls.model_fields.items(): f_dct = f_info.asdict() new_fields[f_name] = ( Annotated[(Union[f_dct['annotation'], None], *f_dct['metadata'], Field(**f_dct['attributes']))], None, ) return create_model( f'{model_cls.__name__}Optional', __base__=model_cls, # (1)! **new_fields, ) ``` 1. Using the original model as a base will inherit the [validators](../concepts/validators.md), [computed fields](../concepts/fields.md#the-computed_field-decorator), etc. The parent fields are overridden by the ones we define. === "Python 3.10" ```python {lint="skip" requires="3.10" linenums="1"} from typing import Annotated from pydantic import BaseModel, Field, create_model def make_fields_optional(model_cls: type[BaseModel]) -> type[BaseModel]: new_fields = {} for f_name, f_info in model_cls.model_fields.items(): f_dct = f_info.asdict() new_fields[f_name] = ( Annotated[(f_dct['annotation'] | None, *f_dct['metadata'], Field(**f_dct['attributes']))], None, ) return create_model( f'{model_cls.__name__}Optional', __base__=model_cls, # (1)! **new_fields, ) ``` 1. Using the original model as a base will inherit the [validators](../concepts/validators.md), [computed fields](../concepts/fields.md#the-computed_field-decorator), etc. The parent fields are overridden by the ones we define. === "Python 3.11 and above" ```python {lint="skip" requires="3.11" linenums="1"} from typing import Annotated from pydantic import BaseModel, Field, create_model def make_fields_optional(model_cls: type[BaseModel]) -> type[BaseModel]: new_fields = {} for f_name, f_info in model_cls.model_fields.items(): f_dct = f_info.asdict() new_fields[f_name] = ( Annotated[f_dct['annotation'] | None, *f_dct['metadata'], Field(**f_dct['attributes'])], None, ) return create_model( f'{model_cls.__name__}Optional', __base__=model_cls, # (1)! **new_fields, ) ``` 1. Using the original model as a base will inherit the [validators](../concepts/validators.md), [computed fields](../concepts/fields.md#the-computed_field-decorator), etc. The parent fields are overridden by the ones we define. For each field, we generate a dictionary representation of the [`FieldInfo`][pydantic.fields.FieldInfo] instance using the [`asdict()`][pydantic.fields.FieldInfo.asdict] method, containing the annotation, metadata and attributes. With the following model: ```python {lint="skip" test="skip"} class Model(BaseModel): f: Annotated[int, Field(gt=1), WithJsonSchema({'extra': 'data'}), Field(title='F')] = 1 ``` The [`FieldInfo`][pydantic.fields.FieldInfo] instance of `f` will have three items in its dictionary representation: * `annotation`: `int`. * `metadata`: A list containing the type-specific constraints and other metadata: `[Gt(1), WithJsonSchema({'extra': 'data'})]`. * `attributes`: The remaining field-specific attributes: `{'title': 'F'}`. With that in mind, we can recreate an annotation that "simulates" the one from the original model: === "Python 3.9 and above" ```python {lint="skip" test="skip"} new_annotation = Annotated[( f_dct['annotation'] | None, # (1)! *f_dct['metadata'], # (2)! Field(**f_dct['attributes']), # (3)! )] ``` 1. We create a new annotation from the existing one, but adding `None` as an allowed value (in our previous example, this is equivalent to `int | None`). 2. We unpack the metadata to be reused (in our previous example, this is equivalent to specifying `Field(gt=1)` and `WithJsonSchema({'extra': 'data'})` as [`Annotated`][typing.Annotated] metadata). 3. We specify the field-specific attributes by using the [`Field()`][pydantic.Field] function (in our previous example, this is equivalent to `Field(title='F')`). === "Python 3.11 and above" ```python {lint="skip" test="skip"} new_annotation = Annotated[ f_dct['annotation'] | None, # (1)! *f_dct['metadata'], # (2)! Field(**f_dct['attributes']), # (3)! ] ``` 1. We create a new annotation from the existing one, but adding `None` as an allowed value (in our previous example, this is equivalent to `int | None`). 2. We unpack the metadata to be reused (in our previous example, this is equivalent to specifying `Field(gt=1)` and `WithJsonSchema({'extra': 'data'})` as [`Annotated`][typing.Annotated] metadata). 3. We specify the field-specific attributes by using the [`Field()`][pydantic.Field] function (in our previous example, this is equivalent to `Field(title='F')`). and specify `None` as a default value (the second element of the tuple for the field definition accepted by [`create_model()`][pydantic.create_model]). Here is a demonstration of our factory function: ```python {lint="skip" test="skip"} from pydantic import BaseModel, Field class Model(BaseModel): a: Annotated[int, Field(gt=1)] ModelOptional = make_fields_optional(Model) m = ModelOptional() print(m.a) #> None ``` A couple notes on the implementation: * Our `make_fields_optional()` function is defined as returning an arbitrary Pydantic model class (`-> type[BaseModel]`). An alternative solution can be to use a type variable to preserve the input class: === "Python 3.9 and above" ```python {lint="skip" test="skip"} ModelTypeT = TypeVar('ModelTypeT', bound=type[BaseModel]) def make_fields_optional(model_cls: ModelTypeT) -> ModelTypeT: ... ``` === "Python 3.12 and above" ```python {lint="skip" test="skip"} def make_fields_optional[ModelTypeT: type[BaseModel]](model_cls: ModelTypeT) -> ModelTypeT: ... ``` However, note that static type checkers *won't* be able to understand that all fields are now optional. * The experimental [`MISSING` sentinel](../concepts/experimental.md#missing-sentinel) can be used as an alternative to `None` for the default values. Simply replace `None` by `MISSING` in the new annotation and default value. * You might be tempted to make a copy of the original [`FieldInfo`][pydantic.fields.FieldInfo] instances, add a default and/or perform other mutations, to then reuse it as [`Annotated`][typing.Annotated] metadata. While this may work in some cases, it is **not** a supported pattern, and could break or be deprecated at any point. We strongly encourage using the pattern from this example instead. pydantic-pydantic-ba0aa01/docs/examples/files.md000066400000000000000000000176121517143232300220070ustar00rootroot00000000000000`pydantic` is a great tool for validating data coming from various sources. In this section, we will look at how to validate data from different types of files. !!! note If you're using any of the below file formats to parse configuration / settings, you might want to consider using the [`pydantic-settings`][pydantic_settings] library, which offers builtin support for parsing this type of data. ## JSON data `.json` files are a common way to store key / value data in a human-readable format. Here is an example of a `.json` file: ```json { "name": "John Doe", "age": 30, "email": "john@example.com" } ``` To validate this data, we can use a `pydantic` model: ```python {test="skip"} import pathlib from pydantic import BaseModel, EmailStr, PositiveInt class Person(BaseModel): name: str age: PositiveInt email: EmailStr json_string = pathlib.Path('person.json').read_text() person = Person.model_validate_json(json_string) print(person) #> name='John Doe' age=30 email='john@example.com' ``` If the data in the file is not valid, `pydantic` will raise a [`ValidationError`][pydantic_core.ValidationError]. Let's say we have the following `.json` file: ```json { "age": -30, "email": "not-an-email-address" } ``` This data is flawed for three reasons: 1. It's missing the `name` field. 2. The `age` field is negative. 3. The `email` field is not a valid email address. When we try to validate this data, `pydantic` raises a [`ValidationError`][pydantic_core.ValidationError] with all of the above issues: ```python {test="skip"} import pathlib from pydantic import BaseModel, EmailStr, PositiveInt, ValidationError class Person(BaseModel): name: str age: PositiveInt email: EmailStr json_string = pathlib.Path('person.json').read_text() try: person = Person.model_validate_json(json_string) except ValidationError as err: print(err) """ 3 validation errors for Person name Field required [type=missing, input_value={'age': -30, 'email': 'not-an-email-address'}, input_type=dict] For further information visit https://errors.pydantic.dev/2.10/v/missing age Input should be greater than 0 [type=greater_than, input_value=-30, input_type=int] For further information visit https://errors.pydantic.dev/2.10/v/greater_than email value is not a valid email address: An email address must have an @-sign. [type=value_error, input_value='not-an-email-address', input_type=str] """ ``` Often, it's the case that you have an abundance of a certain type of data within a `.json` file. For example, you might have a list of people: ```json [ { "name": "John Doe", "age": 30, "email": "john@example.com" }, { "name": "Jane Doe", "age": 25, "email": "jane@example.com" } ] ``` In this case, you can validate the data against a `list[Person]` model: ```python {test="skip"} import pathlib from pydantic import BaseModel, EmailStr, PositiveInt, TypeAdapter class Person(BaseModel): name: str age: PositiveInt email: EmailStr person_list_adapter = TypeAdapter(list[Person]) # (1)! json_string = pathlib.Path('people.json').read_text() people = person_list_adapter.validate_json(json_string) print(people) #> [Person(name='John Doe', age=30, email='john@example.com'), Person(name='Jane Doe', age=25, email='jane@example.com')] ``` 1. We use [`TypeAdapter`][pydantic.type_adapter.TypeAdapter] to validate a list of `Person` objects. [`TypeAdapter`][pydantic.type_adapter.TypeAdapter] is a Pydantic construct used to validate data against a single type. ## JSON lines files Similar to validating a list of objects from a `.json` file, you can validate a list of objects from a `.jsonl` file. `.jsonl` files are a sequence of JSON objects separated by newlines. Consider the following `.jsonl` file: ```json {"name": "John Doe", "age": 30, "email": "john@example.com"} {"name": "Jane Doe", "age": 25, "email": "jane@example.com"} ``` We can validate this data with a similar approach to the one we used for `.json` files: ```python {test="skip"} import pathlib from pydantic import BaseModel, EmailStr, PositiveInt class Person(BaseModel): name: str age: PositiveInt email: EmailStr json_lines = pathlib.Path('people.jsonl').read_text().splitlines() people = [Person.model_validate_json(line) for line in json_lines] print(people) #> [Person(name='John Doe', age=30, email='john@example.com'), Person(name='Jane Doe', age=25, email='jane@example.com')] ``` ## CSV files CSV is one of the most common file formats for storing tabular data. To validate data from a CSV file, you can use the `csv` module from the Python standard library to load the data and validate it against a Pydantic model. Consider the following CSV file: ```csv name,age,email John Doe,30,john@example.com Jane Doe,25,jane@example.com ``` Here's how we validate that data: ```python {test="skip"} import csv from pydantic import BaseModel, EmailStr, PositiveInt class Person(BaseModel): name: str age: PositiveInt email: EmailStr with open('people.csv') as f: reader = csv.DictReader(f) people = [Person.model_validate(row) for row in reader] print(people) #> [Person(name='John Doe', age=30, email='john@example.com'), Person(name='Jane Doe', age=25, email='jane@example.com')] ``` ## TOML files TOML files are often used for configuration due to their simplicity and readability. Consider the following TOML file: ```toml name = "John Doe" age = 30 email = "john@example.com" ``` Here's how we validate that data: ```python {test="skip"} import tomllib from pydantic import BaseModel, EmailStr, PositiveInt class Person(BaseModel): name: str age: PositiveInt email: EmailStr with open('person.toml', 'rb') as f: data = tomllib.load(f) person = Person.model_validate(data) print(person) #> name='John Doe' age=30 email='john@example.com' ``` ## YAML files YAML (YAML Ain't Markup Language) is a human-readable data serialization format that is often used for configuration files. Consider the following YAML file: ```yaml name: John Doe age: 30 email: john@example.com ``` Here's how we validate that data: ```python {test="skip"} import yaml from pydantic import BaseModel, EmailStr, PositiveInt class Person(BaseModel): name: str age: PositiveInt email: EmailStr with open('person.yaml') as f: data = yaml.safe_load(f) person = Person.model_validate(data) print(person) #> name='John Doe' age=30 email='john@example.com' ``` ## XML files XML (eXtensible Markup Language) is a markup language that defines a set of rules for encoding documents in a format that is both human-readable and machine-readable. Consider the following XML file: ```xml John Doe 30 john@example.com ``` Here's how we validate that data: ```python {test="skip"} import xml.etree.ElementTree as ET from pydantic import BaseModel, EmailStr, PositiveInt class Person(BaseModel): name: str age: PositiveInt email: EmailStr tree = ET.parse('person.xml').getroot() data = {child.tag: child.text for child in tree} person = Person.model_validate(data) print(person) #> name='John Doe' age=30 email='john@example.com' ``` ## INI files INI files are a simple configuration file format that uses sections and key-value pairs. They are commonly used in Windows applications and older software. Consider the following INI file: ```ini [PERSON] name = John Doe age = 30 email = john@example.com ``` Here's how we validate that data: ```python {test="skip"} import configparser from pydantic import BaseModel, EmailStr, PositiveInt class Person(BaseModel): name: str age: PositiveInt email: EmailStr config = configparser.ConfigParser() config.read('person.ini') person = Person.model_validate(config['PERSON']) print(person) #> name='John Doe' age=30 email='john@example.com' ``` pydantic-pydantic-ba0aa01/docs/examples/orms.md000066400000000000000000000036411517143232300216620ustar00rootroot00000000000000Pydantic serves as a great tool for defining models for ORM (object relational mapping) libraries. ORMs are used to map objects to database tables, and vice versa. ## SQLAlchemy Pydantic can pair with SQLAlchemy, as it can be used to define the schema of the database models. !!! warning "Code Duplication" If you use Pydantic with SQLAlchemy, you might experience some frustration with code duplication. If you find yourself experiencing this difficulty, you might also consider [`SQLModel`](https://sqlmodel.tiangolo.com/) which integrates Pydantic with SQLAlchemy such that much of the code duplication is eliminated. If you'd prefer to use pure Pydantic with SQLAlchemy, we recommend using Pydantic models alongside of SQLAlchemy models as shown in the example below. In this case, we take advantage of Pydantic's aliases feature to name a `Column` after a reserved SQLAlchemy field, thus avoiding conflicts. ```python import sqlalchemy as sa from sqlalchemy.orm import declarative_base from pydantic import BaseModel, ConfigDict, Field class MyModel(BaseModel): model_config = ConfigDict(from_attributes=True) metadata: dict[str, str] = Field(alias='metadata_') Base = declarative_base() class MyTableModel(Base): __tablename__ = 'my_table' id = sa.Column('id', sa.Integer, primary_key=True) # 'metadata' is reserved by SQLAlchemy, hence the '_' metadata_ = sa.Column('metadata', sa.JSON) sql_model = MyTableModel(metadata_={'key': 'val'}, id=1) pydantic_model = MyModel.model_validate(sql_model) print(pydantic_model.model_dump()) #> {'metadata': {'key': 'val'}} print(pydantic_model.model_dump(by_alias=True)) #> {'metadata_': {'key': 'val'}} ``` !!! note The example above works because aliases have priority over field names for field population. Accessing `SQLModel`'s `metadata` attribute would lead to a `ValidationError`. pydantic-pydantic-ba0aa01/docs/examples/pydantic_ai.md000066400000000000000000000023731517143232300231670ustar00rootroot00000000000000[Pydantic AI](https://ai.pydantic.dev/) is a Python agent framework built by the Pydantic team that uses Pydantic validation for [structured output](https://ai.pydantic.dev/output/#structured-output) schema generation and validation. By specifying an `output_type` on an Agent, you can constrain the LLM to return data that matches your Pydantic model schema. ## LLM Structured Output ```python {test="skip"} from pydantic_ai import Agent from pydantic import BaseModel, Field, ValidationInfo, field_validator class City(BaseModel): name: str country: str population: int = Field(description='Estimated population', gt=0) @field_validator('country') @classmethod def country_must_be_valid(cls, v: str, info: ValidationInfo) -> str: valid_countries: list[str] = info.context or [] if v not in valid_countries: raise ValueError(f'Unknown country: {v!r}') return v agent = Agent( 'openai:gpt-5-mini', output_type=list[City], # Pydantic validation context (not sent to the model) validation_context=['Japan', 'United States', 'Germany'], ) result = agent.run_sync('List the 3 largest cities in Japan') print(result.output) #> [City(name='Tokyo', country='Japan', population=13960000), ...] ``` pydantic-pydantic-ba0aa01/docs/examples/queues.md000066400000000000000000000134471517143232300222160ustar00rootroot00000000000000Pydantic is quite helpful for validating data that goes into and comes out of queues. Below, we'll explore how to validate / serialize data with various queue systems. ## Redis queue Redis is a popular in-memory data structure store. In order to run this example locally, you'll first need to [install Redis](https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/) and start your server up locally. Here's a simple example of how you can use Pydantic to: 1. Serialize data to push to the queue 2. Deserialize and validate data when it's popped from the queue ```python {test="skip"} import redis from pydantic import BaseModel, EmailStr class User(BaseModel): id: int name: str email: EmailStr r = redis.Redis(host='localhost', port=6379, db=0) QUEUE_NAME = 'user_queue' def push_to_queue(user_data: User) -> None: serialized_data = user_data.model_dump_json() r.rpush(QUEUE_NAME, serialized_data) print(f'Added to queue: {serialized_data}') user1 = User(id=1, name='John Doe', email='john@example.com') user2 = User(id=2, name='Jane Doe', email='jane@example.com') push_to_queue(user1) #> Added to queue: {"id":1,"name":"John Doe","email":"john@example.com"} push_to_queue(user2) #> Added to queue: {"id":2,"name":"Jane Doe","email":"jane@example.com"} def pop_from_queue() -> None: data = r.lpop(QUEUE_NAME) if data: user = User.model_validate_json(data) print(f'Validated user: {repr(user)}') else: print('Queue is empty') pop_from_queue() #> Validated user: User(id=1, name='John Doe', email='john@example.com') pop_from_queue() #> Validated user: User(id=2, name='Jane Doe', email='jane@example.com') pop_from_queue() #> Queue is empty ``` ## RabbitMQ RabbitMQ is a popular message broker that implements the AMQP protocol. In order to run this example locally, you'll first need to [install RabbitMQ](https://www.rabbitmq.com/download.html) and start your server. Here's a simple example of how you can use Pydantic to: 1. Serialize data to push to the queue 2. Deserialize and validate data when it's popped from the queue First, let's create a sender script. ```python {test="skip"} import pika from pydantic import BaseModel, EmailStr class User(BaseModel): id: int name: str email: EmailStr connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) channel = connection.channel() QUEUE_NAME = 'user_queue' channel.queue_declare(queue=QUEUE_NAME) def push_to_queue(user_data: User) -> None: serialized_data = user_data.model_dump_json() channel.basic_publish( exchange='', routing_key=QUEUE_NAME, body=serialized_data, ) print(f'Added to queue: {serialized_data}') user1 = User(id=1, name='John Doe', email='john@example.com') user2 = User(id=2, name='Jane Doe', email='jane@example.com') push_to_queue(user1) #> Added to queue: {"id":1,"name":"John Doe","email":"john@example.com"} push_to_queue(user2) #> Added to queue: {"id":2,"name":"Jane Doe","email":"jane@example.com"} connection.close() ``` And here's the receiver script. ```python {test="skip"} import pika from pydantic import BaseModel, EmailStr class User(BaseModel): id: int name: str email: EmailStr def main(): connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) channel = connection.channel() QUEUE_NAME = 'user_queue' channel.queue_declare(queue=QUEUE_NAME) def process_message( ch: pika.channel.Channel, method: pika.spec.Basic.Deliver, properties: pika.spec.BasicProperties, body: bytes, ): user = User.model_validate_json(body) print(f'Validated user: {repr(user)}') ch.basic_ack(delivery_tag=method.delivery_tag) channel.basic_consume(queue=QUEUE_NAME, on_message_callback=process_message) channel.start_consuming() if __name__ == '__main__': try: main() except KeyboardInterrupt: pass ``` To test this example: 1. Run the receiver script in one terminal to start the consumer. 2. Run the sender script in another terminal to send messages. ## ARQ ARQ is a fast Redis-based job queue for Python. It's built on top of Redis and provides a simple way to handle background tasks. In order to run this example locally, you’ll need to [Install Redis](https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/) and start your server. Here's a simple example of how you can use Pydantic with ARQ to: 1. Define a model for your job data 2. Serialize data when enqueueing jobs 3. Validate and deserialize data when processing jobs ```python {test="skip"} import asyncio from typing import Any from arq import create_pool from arq.connections import RedisSettings from pydantic import BaseModel, EmailStr class User(BaseModel): id: int name: str email: EmailStr REDIS_SETTINGS = RedisSettings() async def process_user(ctx: dict[str, Any], user_data: dict[str, Any]) -> None: user = User.model_validate(user_data) print(f'Processing user: {repr(user)}') async def enqueue_jobs(redis): user1 = User(id=1, name='John Doe', email='john@example.com') user2 = User(id=2, name='Jane Doe', email='jane@example.com') await redis.enqueue_job('process_user', user1.model_dump()) print(f'Enqueued user: {repr(user1)}') await redis.enqueue_job('process_user', user2.model_dump()) print(f'Enqueued user: {repr(user2)}') class WorkerSettings: functions = [process_user] redis_settings = REDIS_SETTINGS async def main(): redis = await create_pool(REDIS_SETTINGS) await enqueue_jobs(redis) if __name__ == '__main__': asyncio.run(main()) ``` This script is complete. It should run "as is" both to enqueue jobs and to process them. pydantic-pydantic-ba0aa01/docs/examples/requests.md000066400000000000000000000035451517143232300225600ustar00rootroot00000000000000Pydantic models are a great way to validate and serialize data for requests and responses. Pydantic is instrumental in many web frameworks and libraries, such as FastAPI, Django, Flask, and HTTPX. ## `httpx` requests [`httpx`](https://www.python-httpx.org/) is an HTTP client for Python 3 with synchronous and asynchronous APIs. In the below example, we query the [JSONPlaceholder API](https://jsonplaceholder.typicode.com/) to get a user's data and validate it with a Pydantic model. ```python {test="skip"} import httpx from pydantic import BaseModel, EmailStr class User(BaseModel): id: int name: str email: EmailStr url = 'https://jsonplaceholder.typicode.com/users/1' response = httpx.get(url) response.raise_for_status() user = User.model_validate(response.json()) print(repr(user)) #> User(id=1, name='Leanne Graham', email='Sincere@april.biz') ``` The [`TypeAdapter`][pydantic.type_adapter.TypeAdapter] tool from Pydantic often comes in quite handy when working with HTTP requests. Consider a similar example where we are validating a list of users: ```python {test="skip"} from pprint import pprint import httpx from pydantic import BaseModel, EmailStr, TypeAdapter class User(BaseModel): id: int name: str email: EmailStr url = 'https://jsonplaceholder.typicode.com/users/' # (1)! response = httpx.get(url) response.raise_for_status() users_list_adapter = TypeAdapter(list[User]) users = users_list_adapter.validate_python(response.json()) pprint([u.name for u in users]) """ ['Leanne Graham', 'Ervin Howell', 'Clementine Bauch', 'Patricia Lebsack', 'Chelsey Dietrich', 'Mrs. Dennis Schulist', 'Kurtis Weissnat', 'Nicholas Runolfsdottir V', 'Glenna Reichert', 'Clementina DuBuque'] """ ``` 1. Note, we're querying the `/users/` endpoint here to get a list of users. pydantic-pydantic-ba0aa01/docs/extra/000077500000000000000000000000001517143232300176615ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/docs/extra/algolia.js000066400000000000000000000067021517143232300216340ustar00rootroot00000000000000const ALGOLIA_APP_ID = 'KPPUDTIAVX'; const ALGOLIA_API_KEY = '1fc841595212a2c3afe8c24dd4cb8790'; const ALGOLIA_INDEX_NAME = 'pydantic-docs'; const { liteClient: algoliasearch } = window['algoliasearch/lite']; const searchClient = algoliasearch(ALGOLIA_APP_ID, ALGOLIA_API_KEY); const search = instantsearch({ indexName: ALGOLIA_INDEX_NAME, searchClient, searchFunction(helper) { const query = helper.state.query if (query && query.length > 1) { document.querySelector('#hits').hidden = false document.querySelector('#type-to-start-searching').hidden = true helper.search(); } else { document.querySelector('#hits').hidden = true document.querySelector('#type-to-start-searching').hidden = false } }, }); // create custom widget, to integrate with MkDocs built-in markup const customSearchBox = instantsearch.connectors.connectSearchBox((renderOptions, isFirstRender) => { const { query, refine, clear } = renderOptions; if (isFirstRender) { document.querySelector('#searchbox').addEventListener('input', event => { refine(event.target.value); }); document.querySelector('#searchbox').addEventListener('focus', () => { document.querySelector('#__search').checked = true; }); document.querySelector('#searchbox-clear').addEventListener('click', () => { clear(); }); document.querySelector('#searchbox').addEventListener('keydown', (event) => { // on down arrow, find the first search result and focus it if (event.key === 'ArrowDown') { document.querySelector('.md-search-result__link').focus(); event.preventDefault(); } }); // for Hits, add keyboard navigation document.querySelector('#hits').addEventListener('keydown', (event) => { if (event.key === 'ArrowDown') { const next = event.target.parentElement.nextElementSibling; if (next) { next.querySelector('.md-search-result__link').focus(); event.preventDefault(); } } else if (event.key === 'ArrowUp') { const prev = event.target.parentElement.previousElementSibling; if (prev) { prev.querySelector('.md-search-result__link').focus(); } else { document.querySelector('#searchbox').focus(); } event.preventDefault(); } }) document.addEventListener('keydown', (event) => { // if forward slash is pressed, focus the search box if (event.key === '/' && event.target.tagName !== 'INPUT') { document.querySelector('#searchbox').focus(); event.preventDefault(); } }) } document.querySelector('#type-to-start-searching').hidden = query.length > 1; document.querySelector('#searchbox').value = query; }); search.addWidgets([ customSearchBox({}), instantsearch.widgets.hits({ container: '#hits', cssClasses: { 'list': 'md-search-result__list', 'item': 'md-search-result__item' }, templates: { item: (hit, { html, components }) => { return html`

${components.Highlight({ attribute: 'title', hit })}

${components.Snippet({ attribute: 'content', hit })}
` }, }, }) ]); search.start(); pydantic-pydantic-ba0aa01/docs/extra/feedback.js000066400000000000000000000007731517143232300217520ustar00rootroot00000000000000var feedback = document.forms.feedback feedback.hidden = false feedback.addEventListener("submit", function(ev) { ev.preventDefault() var data = ev.submitter.getAttribute("data-md-value") feedback.firstElementChild.disabled = true var note = feedback.querySelector( `.md-feedback__note [data-md-value='${data}']` ) if (note) note.hidden = false if (data == 1) { window.flarelytics_event('thumbsUp'); } else if (data == 0) { window.flarelytics_event('thumbsDown'); } }) pydantic-pydantic-ba0aa01/docs/extra/fluff.js000066400000000000000000000042651517143232300213300ustar00rootroot00000000000000// set the download count in the "why pydantic" page (async function() { const downloadCount = document.getElementById('download-count'); if (downloadCount) { const r = await fetch('https://errors.pydantic.dev/download-count.txt'); if (r.status === 200) { downloadCount.innerText = await r.text(); } } })(); // update the announcement banner to change the app type (function() { const el = document.getElementById('logfire-app-type'); const appTypes = [ ['/integrations/pydantic/', 'Pydantic validations.'], ['/integrations/fastapi/', 'FastAPI app.'], ['/integrations/openai/', 'OpenAI integration.'], ['/integrations/asyncpg/', 'Postgres queries.'], ['/integrations/redis/', 'task queue.'], ['/integrations/system-metrics/', 'system metrics.'], ['/integrations/httpx/', 'API calls.'], ['/integrations/logging/', 'std lib logging.'], ['/integrations/django/', 'Django app.'], ['/integrations/anthropic/', 'Anthropic API calls.'], ['/integrations/flask/', 'Flask app.'], ['/integrations/mysql/', 'MySQL queries.'], ['/integrations/sqlalchemy/', 'SQLAlchemy queries.'], ['/integrations/structlog/', 'Structlog logs.'], ['/integrations/stripe/', 'Stripe API calls.'], ]; const docsUrl = 'https://logfire.pydantic.dev/docs'; let counter = 0; const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); // avoid multiple replaceText running at the same time (e.g. when the user has left the page) let running = false; const replaceText = async () => { if (running) { return; } running = true; try { const text = el.textContent; for (let i = text.length; i >= 0; i--) { el.textContent = text.slice(0, i); await sleep(30); } await sleep(30); counter++; // change the link halfway through the animation const [link, newText] = appTypes[counter % appTypes.length]; el.href = docsUrl + link; await sleep(30); for (let i = 0; i <= newText.length; i++) { el.textContent = newText.slice(0, i); await sleep(30); } } finally { running = false; } }; setInterval(replaceText, 4000); })(); pydantic-pydantic-ba0aa01/docs/extra/mathjax.js000066400000000000000000000006001517143232300216470ustar00rootroot00000000000000window.MathJax = { tex: { inlineMath: [["\\(", "\\)"]], displayMath: [["\\[", "\\]"]], processEscapes: true, processEnvironments: true }, options: { ignoreHtmlClass: ".*|", processHtmlClass: "arithmatex" } }; document$.subscribe(() => { MathJax.startup.output.clearCache() MathJax.typesetClear() MathJax.texReset() MathJax.typesetPromise() }) pydantic-pydantic-ba0aa01/docs/extra/terminal.css000066400000000000000000000010231517143232300222020ustar00rootroot00000000000000.terminal { background: #300a24; border-radius: 4px; padding: 5px 10px; } pre.terminal-content { display: inline-block; line-height: 1.3 !important; white-space: pre-wrap; word-wrap: break-word; background: #300a24 !important; color: #d0d0d0 !important; } .ansi2 { font-weight: lighter; } .ansi3 { font-style: italic; } .ansi32 { color: #00aa00; } .ansi34 { color: #5656fe; } .ansi35 { color: #E850A8; } .ansi38-1 { color: #cf0000; } .ansi38-5 { color: #E850A8; } .ansi38-68 { color: #2a54a8; } pydantic-pydantic-ba0aa01/docs/extra/tweaks.css000066400000000000000000000120771517143232300217000ustar00rootroot00000000000000.sponsors { display: flex; justify-content: center; flex-wrap: wrap; align-items: center; margin: 1rem 0; } .sponsors > div { text-align: center; width: 33%; padding-bottom: 20px; } .sponsors span { display: block; } @media screen and (max-width: 599px) { .sponsors span { display: none; } } .sponsors img { width: 65%; border-radius: 5px; } /*blog post*/ aside.blog { display: flex; align-items: center; } aside.blog img { width: 50px; height: 50px; border-radius: 25px; margin-right: 20px; } /* Define the company grid layout */ #grid-container { width: 100%; text-align: center; } #company-grid { display: inline-block; margin: 0 auto; gap: 10px; align-content: center; justify-content: center; grid-auto-flow: column; } [data-md-color-scheme="slate"] #company-grid { background-color: #ffffff; border-radius: .5rem; color: black; } .tile { display: flex; text-align: center; width: 120px; height: 120px; display: inline-block; margin: 10px; padding: 5px; border-radius: .5rem; } .tile img { width: 100px; } .md-typeset__table > table { max-height: 60vh; } .md-typeset__table > table thead { position: sticky; top: 0; background-color: var(--md-default-bg-color); } .md-typeset__table > table th { border-bottom: .05rem solid var(--md-typeset-table-color); } .md-typeset__table > table tr:first-child td { border-top: none; } /* API documentation link admonition */ :root { --md-admonition-icon--api: url('data:image/svg+xml;charset=utf-8,') } .md-typeset .admonition.api, .md-typeset details.api { border-color: #448aff; } .md-typeset .api > .admonition-title, .md-typeset .api > summary { background-color: #448aff1a; } .md-typeset .api > .admonition-title::before, .md-typeset .api > summary::before { background-color: #448aff; -webkit-mask-image: var(--md-admonition-icon--api); mask-image: var(--md-admonition-icon--api); } /* Logfire link admonition */ :root { --md-admonition-icon--logfire: url('data:image/svg+xml;utf8,'); } .md-typeset .admonition.logfire, .md-typeset details.logfire { border-color: #e620e9; } .md-typeset .logfire > .admonition-title, .md-typeset .logfire > summary { background-color: #e620e91a; } .md-typeset .logfire > .admonition-title::before, .md-typeset .logfire > summary::before { background-color: #e620e9; -webkit-mask-image: var(--md-admonition-icon--logfire); mask-image: var(--md-admonition-icon--logfire); } /* Hide the run button in logfire admonitions */ .admonition.logfire .run-code-btn { display: none; } /* add border to screenshots in the logfire admonitions `img[src*="logfire"]` to differentiate from emojis */ .admonition.logfire img[src*="logfire"] { border: 1px solid #448aff; border-radius: 0.2rem; padding: 0.2rem; } /* banner slightly larger */ .md-banner__inner { font-size: 0.8rem; margin: 0.3rem auto; } /* Revert hue value to that of pre mkdocs-material v9.4.0 */ [data-md-color-scheme="slate"] { --md-hue: 230; --md-default-bg-color: hsla(230, 15%, 21%, 1); } /* Add customization for pydantic people page */ .user-list { display: flex; flex-wrap: wrap; margin-bottom: 2rem; } .user-list-center { justify-content: space-evenly; } .user { margin: 1em; min-width: 7em; } .user .avatar-wrapper { width: 80px; height: 80px; margin: 10px auto; overflow: hidden; border-radius: 50%; position: relative; } .user .avatar-wrapper img { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } .user .title { text-align: center; } .user .count { font-size: 80%; text-align: center; } /** Algolia search module */ .md-search__input::-webkit-search-decoration, .md-search__input::-webkit-search-cancel-button, .md-search__input::-webkit-search-results-button, .md-search__input::-webkit-search-results-decoration { -webkit-appearance:none; } .md-search-result__article { padding-bottom: .55em; } .ais-SearchBox-form { display: flex; flex-direction: row; gap: 10px; } .md-search-result mark.ais-Highlight-highlighted, .md-search-result mark.ais-Snippet-highlighted { color: var(--md-primary-fg-color); } pydantic-pydantic-ba0aa01/docs/favicon.png000066400000000000000000000015541517143232300206760ustar00rootroot00000000000000PNG  IHDR szz pHYsR}2IDATXWKhQ~PTls hUDPW. K)(Rԕ]ƕEPDD4}so:hwNd&ixd9ݹUN {ڨg8H?ҊܫT"L>_rJNx*r~Ӟ)yC0Rs Gﲚf[ h3Z0Nݹ# B!w +kmC0_{fUEnT4YM/}.4"CsXU_H ;M~ƋkgclI|Y&e_ |@ !2L:S97VK\tCt^ɵbI1Z񫠀 0#l=%hE´ѥĖ+ýZbR\&R$of1a81V{ ǵ0`$FRvǑW0S֩ @'#4P{]T Gۈ9X<KL/ޙ"mTcnZ>'5RyGubcsͪ-4h _@z.0R2u~/^eĜ&ωMtƋូ]r/hyPqn5Ynf}k'@j Ő~Iz_!u!5 BIENDB`pydantic-pydantic-ba0aa01/docs/help_with_pydantic.md000066400000000000000000000021471517143232300227420ustar00rootroot00000000000000# Getting help with Pydantic If you need help getting started with Pydantic or with advanced usage, the following sources may be useful. ## :material-help: Usage Documentation The [usage documentation](concepts/models.md) is the most complete guide on how to use Pydantic. ## :material-api: API Documentation The [API documentation](api/base_model.md) gives reference docs for all public Pydantic APIs. ## :simple-github: GitHub Discussions [GitHub discussions](https://github.com/pydantic/pydantic/discussions) are useful for asking questions, your question and the answer will help everyone. ## :simple-stackoverflow: Stack Overflow Use the [`pydantic`](https://stackoverflow.com/questions/tagged/pydantic) tag on Stack Overflow to ask questions, note this is not always monitored by the core Pydantic team. ## :simple-youtube: YouTube Youtube has lots of useful [videos on Pydantic](https://www.youtube.com/results?search_query=pydantic). In particular Marcelo Trylesinski's video ["Pydantic V1 to V2 - The Migration"](https://youtu.be/sD_xpYl4fPU) has helped people a lot when migrating from Pydantic V1 to V2. pydantic-pydantic-ba0aa01/docs/img/000077500000000000000000000000001517143232300173125ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/docs/img/basic_logfire.png000066400000000000000000002062211517143232300226130ustar00rootroot00000000000000PNG  IHDR d 9PLTE""":::HHH***7BV3AU8AR111Tesss6^w@ABqqq===$$$&&&,+3czUUU???kkkΑxEEEv}(((222444III888ddd-..RSSPPPLLL///ggg]]]XXXCCCuuu[[[aaa___fff666iiiZZZŪ|||OOOZcq,,,8DW~~~WWW;FZĦccc޽nuKKKooo>I\mmmαzzz"(*duISennnfmzBBBKVfks~AAA晝{NXhppp^guM\"AKwwwւ"5;hp|GGGAL^U_nNNNCN`ryR\kx~FQb,18閚4BVԋt򠠠?NWpwz{|˛ḃmqckx1+)06=񣣣bKBȎtcTZF>eV7ATB72(+-;HPyeDU^K<6hnsa~i%@Fv`iwmRGuXK91-Xu~]beW[^zM[i9CJ~^P39E4=A\ziYTm{Pgse`Htn\>hS|SA:7>MLal5?Fp4;@4Rd\凤5\s8`y<| LIDATxٱ 0 AC 3riEn_f Ў2@;BhG!#dv Ў2@;OYB&02wĬUjՌB&cԺjDC"ʍSQېɘ~ p5#!31 0H#D]I3,V 0{ C:L`\BHu PGu PGu PgUۆ ^RO"0c驔NJhJC(%]LХKDW^A/ґ]&v넾Ϣs·@!`Aj>\|E@땾!(ˆhJaJ&oʰetd'.|uݕripyo]8/:TTUՑ7dH{`y_vɖ?2Ou`_&!s1f y{jbucT(=@%h8JQuRM s2-GQ݊$6z9f F2a>!L#v +%LW2bUO$4"Nk Fr !.쳌0{2̆jR$VC&/BDf3%9݇酒cHWՖmnzNcG5שwrʰ+bUU+ӄ3c̥jӤZ៵\$4R2ڄ)'3Fƪ{Պ"W6 q~j?ɺtθv[E*HA^D]AdO=o>0]RhWZyF[7"""UQlm2WA>@lUc%n v$kVpq P JR25$mZ>rNVuU,rڋhI`{yWdԊ9BbmNVdYGfU%a+6f]Wd^(vݳdL8Q]݇]!""""Z ㊤誐_ JTC@[gI/| Ǖ @hY2Qvrw=2CYC,{dv?Q]`3""""UrQJOҼ2"d+h!Sm~2#6()veEsB&sTh[BDDDDR*d@}r>xh!ߠ 4'!_fJ[O&C7O$ օh<[ӴTl塌Y Lߝ0B 5d61/[]v;2B`)BDDDDZ-2i*d%{OMo #7uG2H، v>3WTۂ˟V, )K;FDa17(e#r]['g qP?{21WȔ!!CDDDDa\TM#).Мo>26HYsL ɱ Q2DDDDCIՈ$!Ӆg1sƐ)Z2K9Of2fpLrT  ,IBF!'Zn|6:1ؓBF:p&ѷ\ȴf2ŝ$X$޴""""Zj]U9ol[fVȴBf AC3Sȴ< ^WE~H$d0J,X?2 53dlIh(JB""""Zj*GI [H(˱ݬCI胷l&"""%WXl]ӂCFJmK]D~!5ǃlN. z+B )V+*2vf}Gd#m be˅ZP໒`(RJ!?2.晾P/ϙ7͛bNfQkL12""""Q%>dyBhђY6Z0'DDDDD ʋLؗ۫2Y"""""ή4 a!Kޮfqw "Ypr%2xoErbP |nyB>ʣUȤm 6y=%3bin2t5ߟy"dNS|8oh,Zteι2@$])dhw-fI !#dp 2@8GCfH3 uI)Cfih(C.V&em$ YCÅocDL/[g*PL>S!Idt'2M{j<8o 0L20!3_&۫c,F2r !,G2r sYL̑\`ەo!S`272`:[ҏ!S>;w0ax &Ju/nB_.&}ѶiEZ/1q=2 AYLᵌiyneL뤸Oy7EcHzKtc IXy'2 =󉗫 h !CnPV0d!Cn*G[tLitDdAY;BdB2_-jnJv4v2Y`I B5SmjymOMS(4 FFL)UۦaքE-ښ8 ZꙂZ_2H^fӇ]N~B&0z2bG!st e)$90cuIZάmbUR|G!cS"#  ed5 L|bk˸C7(0DFY )B.H)Ò{ @z@$!}0\#%ľ+|^ɚ?B *)Rrv߃S*$qOCm,`=u4ށ&;v\֠]BS7`H0+|(%1oV{hs뢷hI-;M FVOk! /a2y_A#h44Wr+!BI2) dd2*9;KtTڔ#!#5JjTLw UZ= f#njx8'R.SH-*PTI*շ Ш$=d`>CQGfzCg=4U!8@VXORZ]4AJ 8~(ςÊ5 =!ӯm3zE7)̠MZy?Du,R&e`!r2Mayr-'CJ$e\ y LxȔR< QLt;fip&d2gtQN&aPѕXWݬеոI2 Λ.BJ0[˴#l(-铆$XQҴz}weBܚ`Oiͮ!YMbE! ZY'G$_R u OLӲ-d&:y_f!Sk0H2G&IUš{dc0)$ </C!ǣ4@N*iV~R=`bj.- xO4uoܝ1.F-|(w=֟,׳l#/WD`BY3TML/(͂Icl֥ʪ=!8~(xlx:Go9OL/kZol({EðUلڒƫ#;o?.]Z LxKQ\2w cz~Jn oDQȀC4(^C4d .)]/p(dBPuuʣ=SV`uՋWn9 mS5_5| rJ5XY}Sh cL 8v( ImʚV~l3 t+>^E9O gC&Wek(_'M{؏8C&fx9e& \o&%!ڋ<l0 Fk4r[]!\)YB&Lo 0C&5<<̐yD?!3AZҰ+1N &ͺ`fG0x` :=;ƭ$̐9p:ƽ+fC&3 hѫ rڋHFX.;yjELz'.M>pp % *ʉFfF_e;;zhWdz@w/mq?dB521W/"QDrN] JֱB/\ҫ]؋j7 ^zb ;IW8/((>}wsR"31c*K,Uv-4]mMxr6A!Zna2լ>{2SlY5 2؀ 9ub翢]2wf>4 mjr\=e yU [?lЧapC ]({d:g50wh16h?<7%;.|xVtGU=F|D_znâ`߶F& Yt8 @O[L=_Rn2 jB&DKaa۳D.\P-`Le=e64V>orerVὐ|!#q)BGIfyf3~"%\ K'Cf0>Ub1̎ *L .hhpcZ~{O]c.ONPX% h -Vt𬧖uC%fȈT}eڄA: j^X:@Eg|pch.(.D|NyP7AӺ+dLt0d2CJ2C$6SfM SHs ({.񷖍lkPuZ=7E+dLt0d,2s\rC` T Dt*M xkԲ6F!d*)o=r`8t'6@d;qB ƪ}/{؆܈G.tr=k!Ó͉ om[/d}| zhze$uRW#A]<</&E-򙭶V^X:EEĎYBHBT`/RkgpDx #?0=t` ; yJpf"cJIĎؙ·92Y/m K0޷gYûa( 9\DZﱖ_1JAGFI`SI +* kbӈG, "^Ļc\,M2oiRV&_:iˉVI~ E2dhX>2S?) {)Fm-$3dC2CfeҬal)"ޒ :dE4d~c` @2sHf!j*H^&2o2#HC$!9$3d)2"領%ɬL"/v , $3d Q[2Lu&eȀdQ 9$3dL]C]O=dz.!EdC2Քk  w2 YHf!9$SMѲg8YƐ"A2sHf!j^6d<5`x Ð`q0ۥ\PEACqHHq4cWRL◅A,ґ,B ֲL⁌!dk!Y:#Y:!S^6dl5$KGt$KG63dnKƎ1dN2$KGt$KGb_-` $[ ґ,ґ,o-{hLxsq&J9L>|/O>=6=p,٥JdJdJ솆L[;;C&w3Yҝ,Yҝ,YbҐ)7c g%KwVtg%KwVtg%}v##a8濇 ̺^u ɐB!nvȌu_qv\G2@AF[:ڃk~@s\~d 2;9c8,SS<Zmv!PÂ80Q!l (Uʺv^v!Xw Ԕ(z܊"2w>g3",9QjκI$܂f+{Ǵ;hkFf{iR6yG\Ac>=ӃBMxz?VɝʂlX{ݳwt6&[r_xپ`AyDy?\fetj{øާ Ögi>-2dvڂtq=~Pt\IsPv|Ic~w<|P %eSõJ>Zmv)HwުTVq2(r6z`:Uc,ue#}z!{%B+ 'd DpץC: 3b~^cѽ 4E aw( cz4(銐϶|D*{gǨaQ3L$_}|%Bnd4 3924qUK92P2~Hqe 'iD1[K3e.iv"2P`7vĿKF&"'H kizat \F0;Ykb[4tP % q)ȴ0G\CGLs WOdEQ*"n 2n$t=+s҄41Կst =dQ`*>(4޿~ V!AmvIeq.5h(ҧǬV]:ָi9H}*(Kvـ4qUKpX],1u jտ-pQiqXF֙ 餃oth{d`pR _ 2 q 2(Y/]1rw6mQ1u/ r#Yeg#c6XI؉s0-C0``BN&@C}k驗@r걇 %-jgG]]iUBfgfgf!hQ(3-޸1e6ڴ@;dAMS_8ג/Zd[WOzui4njdE"2dWGFP(,Cv"~n>f^kK "cWx"_1N^"$rSNd!i9gzy(@!?zM]*NvȢBdzEd1f!2pP"CcycG4Ǯ "FM1!208TGdp$jmzgS+2[SFf'8܃JlƔh8_JҟN`2I6蹑jDe oA,["Nւ!zf HޑM{L(U3;) A瑿j {+<7@#En;f D‘v 1x7C5EjBP(>aN2|2RdJLC-v7 Eѝɲ3v"xL%i/1 䏙ɬRO0-}^d%{ ķqewPf}U?\L腉>)2*O:n-*2=2?a'_~q/2Ii> "G,yrk `8vYq o_X"Cĥc=Xqvm>ݒ"M@(/fq}I"H/4%2Ep6٨{ e|:"c j^dyׂ_yHdN1-]@kIqML؋L\4A = X`bM[s{dF-Sb`Ȑl"p : TdbEmjVD9xpkjLSP(8#@ݖ"[,@ 4w1Td{d>cU""4!2$C }hyׄ?4%2eO<\>d4; {9#1g8.S#&q ak;2 ͗ #ZEfmE&E},24t"l&!/S.DFvf2@ۥ@v]_bـZB~qnLa3f0#eDEV{k#FR"P( ;0ٲԋkG99/2C% WCEfalsix$2it7sM , g@j aۡ-24Va^~S/ՙ?7#2pZAD "DcUd|`ar ,"8OLHRɒr& #䗖B@ [KܖjJHuWx[8ȽT${?k"CB;rK|] LwRLn"JYu$%͑"7/ϙ\6<܅L4C"C&Q) B6V>l"SaJaGvLp?Ю&MLx gBkluyb]!`&{e0h>ȼiW E&+@/"{=pBiL$q6u;Ɇ}ULᲞ~E: 8쏅+5EAڰDυuslyb])"ӇOmEf*E1PA`?HdH`{zLn"2!?Fpv{17F%=B݈VImE&I.,Ev"cD)phu5|{dtS?OAፑm7R*Be(Km0IS@ *4px"zЃ^hb?a$خ}ݶT sb2;=Y!pTk)No5r:PUG0cMOåҐl)l9u#yec,),Ω!O (_!c)7XYo4d脈w@x|ZnGaV5rRC&(D:YN0WwdȨ8X[!Y!I!]!Ӕ 3WX`͸f]x~MY7r;&d$6B^ I:'8Vuw9-N.9 #z,C4 -w-AT~ (9kC 6RҮٟLm#.4Ki4@RrVè,]n2C(k>(f"td ZDc{DXBbl`5@oB>?뇵H@LcxVC |}jY1q\ ,Yi(_}>?$evC1ر^'d}Q$!G q\yOC&g%Ҍ"JPBjGO[!&o:ԛN\l!C& 09 bT?dd)emwD p;QޡKAv@H[PPS˻wdDաo#xJHKJ2uЉ簇"祿~c(wK.}Ajެ*1ӥC1 4d(c c1'М|:?.A4{Rkr~^̖+xK"gg DD7~DLÁ!ਘ&q<jXC&$DMR2Ac$6D CipR~{!>1jU4;8dJx5Qqw/`xZ CN;ېq. ʎQJߑa1J#&x,d>rZϨ]3Ґ0JZ )%:yTޒjƣ0<8b.,3P k|L9ccL [!#KExyk{{K~9P5cTB_?>#AMͼ G U'x4@<sds0Og1Vǥ6Bɳ2d*xP9;*^`E† iBg(y& c10 ݲn\&C1vMş<#;C @уwavaXa ww_!ïL! dv"Rc$ y1BVY2쿐 3de!#E~-k d!sGBH2#d< #GAnԃB2@#dC&&2 ػ(8?LGX;; *,媍mb-74HK Bc'!z%(z>DV3Na~TۗyrŨ5R2A*dDD!#"""F}{w`/\.;po)dDD!#"""FT33S QȈNB+"} G~;{g-zi$l_*ҨďoLoIJI(dDDD!w`޼ʷ3-!BiDq{ZYzj=+ualzi1ӊ#W'iϵ2QӖ/cX+)/^DBFDDDj2W>E=1C&1h+3+bꟇ-sN7O腧>ԼN*~Zs0\m~\#tm6"#µN$RG2"""RÐ1e75dhlEY&2f| /m +ķ#8 ʞ|W9F;f7&d7$R?2"""Rː1%sy/1j2k4xNuN\+7vtt9j\g Ke Q;Kty'Z`a~>:֤p 2<%)x<]{ 5n.2CQdHPȈHC\$ D\6Cr6TȓT2/4"Bۣ+8R,.p]~/aXqX8U: Łíixk o'Pkh{~y0`o0b1FK4*ik>qeY/:dzy=t AȜmnS2%\!Õ/d[pu9tC ѵdja"dEWDD23n B -~TaBkM2ȫ4xIr't Aȼh#/p\Ne= i<#)=<,^ hd"d6y 1"Cxb,d3XjPNV (|ݐEy\$R72"""R٦?pU.sxBaw `Dfb>2dZ9OV9dDBF~w?Ma?@gH6u?l9A*nI(("Lˎ^Fɋݼ m0$%ϓfkKDDI ǫgg%V2ۨG>ȹT E0{ |٫Ƈmkzg,5?Fw3'>d,8C2ؓt*-xo5r!#~P[hM*ԟƇ7q&-ixrC!{o)|d W^N C yÕg|BfEND!""D|c yEK\[]ٲ'ђ3G_6>p9%{-k{n%"drݕJ=p" %"d |KcR-Q([;+M6b<{>Ui0G[RogؐANz4ղweGrjI?l~ZPP#;#J9(*~r{ٕ35I2M9zt|{Ql0d(!]WDo`2/dQK;"ji#8"1Pi 'E\]ޏeCxfMEҰW;++:3.<2cdHD F <`薬E̾"C.oD """JHŹ )elSZ,Ae4WDYD*,#{Q{н"R)>P>`s%p"Ҋt'`QbB?rJ*"f3Q|0d!_'zc nmD)fQ0d!ck .7@Dw6'aC&Ɗːڪ"B7(nD' """bQ0d!CDÐ!""" %C2D8 ]E8v iߓ6.XӫnWk+{n2D\ )Po`"Em<ư5ZZgV31 X"~Wj'1d(2DSk ,j|Ԭ ¨W2jͤ!SPa efÐ!Chƕbjv%d4mIi!CtC CF[d0d[ &a "=Y2l!ADAAWN}񘘵^`&7Vj]Ɛ!z3,.BFoId{wo:9ķ 8h]}:]yRzFpfeɽ{;XHg~<,{'b~;RNয,JA*w*{ NhX!%סHtZGըx2+bU,iU{ކ޶ /TBc,>v[| LLѭiX\a0$bc Jpt₾Ϙotx9|ϐ8nU[DyM$Bɰ,=g~2E*Olgn`|,L) 3+^RI3<ɇJmǑhGa$"]{C9[3-9H\Wiusʬ 0pO:^6MAD "zX L-d=1?*- 5{}{dB D&3vR;fLeCfAQ c3-޼9"*F~Lbش32 @]E<slk g+uH@Һ+->#S p(qWcbQ>o:w}ͤ a "bb d۾ +J{X+s[Lʁ>"3$/fھ{211b *ʿRAr C&"1bJ)UJZCm I W̆Y S&,][U)k2D2D? .CfbiUyhཟ3S O_L{ȸXHߦQQct% k @rK8"}H>B['@ߘ!sHe˹|2;[f+ISyx_صdSDĐ!Ő!Qȸ[tmȜ0X)|),/ |ې9&m 惞2/C 9nrӟ_"!sHmOI~'djWfEp_Ux5mSCCG!#8T_*V%_x@Alm rBFt~ !Sͧ# ]_ӷ'2" =6 CFRULo(8"-dz>xDf_2LED{XLKX |6d 6ko}bg fks .dB *djWVcL1;7f~^X︄MS\X!CD!CӐtI8 k-`{xr *+Lj|HvACfK}Kl0C2n>`z@_3$_A⭀=V6uO>$E{Ԯ^/0o9w}1|N= "bCb8d$Ar:^]rvg\TBF`6~WK{${ퟑl5[!s2қ$ZR' 'Zh)U(c-73 +\)LCve7GL%w_m箯]+)w!" =$ jJ]W_|bndm' 4!7 ۿז_}M=VZ!CD!CDDD "0d!CD 1dÐ!""" q2DD7u@ vB`GdvD`GdvD`GdvD`GdvD`Gdطa "C299 %%(ҌZq*$.˞6x#+a}&Asq!ҍa:[21?|2vĬ@u[2qRY*0EB]DƐ.70kMdU-M),qe\ "]00?ЉjEV2˻`HQ̈́ /iN;Z2YԊ9y2'6 `k̷,28uZ2Vs8HDc^"␙]͗wi2'St"d]D߅M_!A[5\odA~7}2@Ln c]4\ĆfBK`ax!wpkܺ1Qa*xHZ<WfQVvPG/E>_`Id5&Bm݌:>5"ic="+ 2B!* s=d$R !+$ B!2)d.[ߓA!C.O7 !#0y_II>:o\Kd_ށߓA!C.O @!C7Ƅߡr(d/P2 b"Ncl2v'x)&7!~3txf@oX_RG$EHs )UR*?ϳveVc+8V!x YƥHpP%IzkWLt~\zQ.U2p!/(ubO uYj^ 0X8~SV Vf'qtκ_-S5lsCr"Ue+ն$oUμh(@ڇPoxԘker\ղSR7ԧPX E}%w'Sl !侰pVɤ.dތKw5拏>:*dtflP`KHj!sQysmQLj %z0uWɤ㶐)!;EKGo3d bTM^WPMP2 2/7X[i~}?!3Le(ҲR/VUdŮ s͐,,VU螇ӝ,vhakƲ`\nqhLsJ6[| KeB22+ f>64wXb1Ll1'UK1/Us :Z_!g.dr8f]%l; }3dʨ\LuL+zt52M|4 E2;5(/Z }i<f٘H +MCZ2!#$dЀMOb‣=e/'[mM2hWW{՝>yZ_d#°u$/s*;Y=sǤZ p1R-W<*Ϻ85HcșpJ?NVfe=OI[˴I\l洺6Ѕ~j!rrhB22,gzR\Z뱯U]pޚvL343ؗ߈w*\Geį:9vεenԷ,gEἶl 1 (B"L}#XHL:7hj>B:MˈלLCߡ6ѦPL3\ l-Cg\)On怌Z ߢ1 IVV&bD5 2F=|j\m(]/_.,= n'4~;ǐ7v>u-_l6OȼE{/g|й|usYyL>=yȨ/?v$~t/_dT?v PDCn(԰w@ a(628-RC02*X\SFP٭Si&y_A c%n it 钲mB@CX7=P؀dSXB!4Xg,J1yYDL2yHC,3`$_|껮 6qvHP.J&d/^d40$Id*p6 1*]( XA´&P^ɬѳCpJ` s8fnlz&Lp0͟fȅ}`:xzǎݕx1)Xd nV2Ruhg˵PZ˗oZ`I|A>+7z;,?2pL:~#7[ ў`2/.f>^|{|x\?>x!cmNwo8Ȝ†ܫ?Ɨ/_L_2&$RxVWoan:uP i0R$;S'^AW5sP17* \B[cEXPjhnL/%Z93Uf)cIZўACt`^>VkF !HT̼dTCXQ(V>k2'8+iճiS.[kiA5h:j .9r-#-$ 6%HExJVzx+WrLrYd,tua2}h:: 3cb~I7^Dhp´(2 CF1 yE9+ [\ &? _^YKD=v_UĘZo-k*V)3JdzX1XDY;[b\6sh6RT~n:}e2yEyGrX>ak{؃ښw}ӱ&>:g2gJo#_?fyЇKc=~Og >'x?]9RTO^,8c-5gbءx h/4TC; k@6Y욃•!sEX`Ѝl* c}c2<೨:i/#0' ^i;b#'pcO aL'/՛yGu,XO pEP7U 7L͎S\Y@\ܤݘc-O Jм JqyP(Y#"E2|p;OQ1Eze֠̎82YgP!_rl k.=vDL~iJ]ZLY&%c34f]M6 Ud|E R❿{sFw? ['4z%=hD*2/qd|z* \/J+[Nq~Λ=ܛVv[7@ V/&a#p,/gtpUh/T̔""$5&H+In XجdH4c{˧JGt<=r苃t ԚN=dL:;BG ;fBF$ d*bi| 2i4搬K14Wvq-d(sC1MRr>.L3͔h!0EfiC1{]k|; =]u;6 Af~Nw1Лjp#xS纑@ 23gTUL@,c!ߨ*?˗/Z&*|27)P/N oN 2S&ȼp-ֽ52T.?eB/AJ࠾ sWW #dkڣ ˫7C?!a2"!10-yz%]f3D2EfWM:qж UTT4T`l $ >꺳㪀8ИFS9 #:Ad1\:Ѯ ׮qJԖZ&vTw@ 2ٚ5aIDȤSO7T^^^Fy QGjЅXV",Dž2'|DoU,PfHUZn*̕GQS`~V C#zV8<&}8PPPTR PBuGPAƗ/_[Y= @:_ٔQs d z*[AuήE|ħ? ʨ&ϔQb|=p}%P}KYRmRwˠw`<; WWԒݳPk{ΒlDC2L&Ů6 KR "xT@l7pU=4$#rA͍Yk2u:;.Amn58_&ghXj0jXЗ CrvU.ȸ2-D%n̏7UvFF xx|_`u$T!$iԦۇ _~GH`Vt mLW5ߨI%vT# ˗/O Kɟqadq=boɫAH?^9d:;w}z*!Y$=xbkSiN!!J:4DNө"C# \LÂbګ|툒`|ז|sT:^.=_5wI2{p8OtzAFN瘎edP_!p$̩=? >! Ҏ2Ǖ|=pQoftTͲ;fWYÎ̹~kPQT=# FKmT)rzBIcqcñ$lS޴,JiTB#5!~s qgX_4oSy:QjrMlƂe-+{Q֝CuaKjQGI6Tcwi+2DќKa &,["gqG lJm꼯(y #ٹS(x'cGΚF< Yw[NcǠ%<䃌/_lbK@&9専 qB{H <cp,1ˇ #ZG" LdT6T~,i?_qZ~Ɨ/_LdI߫=l@`ɬiӔ6 ~^k`D}F`vR{= F3 b 3aJH̔Uy츀BĎA'J_kAE|\P%xP$F==dYpB/<"9T!iN!aM ir K8;wAdۙyo:e?̼v[xpGcިȰgL@f f%q"Rt)@ƧZ dtELs %d$fG4_0O2qg SGo t<m2T|aDD'^ǨIX9ee6tb0PWBŐf*1"8JU d6mmԈ9Zwn4?rtFD#P;Q#:+ŏ n>DmBZn&}tY[Kc7dka"Hew3=S2d;%{8%cŝq"jϒqW{\"c)??ZVFM92э m"5G؞8a58a^&إ(, /J j'nĚU< nhqr3U#xogЖAf)ކ@˖&FA\rY9VzEΓϟscD$I梔#=~,~2 ;@:݌ϲ^%[b7,ZA֥ j>}2M~%9G7/=k6R|˻œ{h%cTIEGw[.4ϝ"r1dd #N`2<  }gÚxX~}g%H.\yЮar-Q9;SЛN=Iͦe?c$w?72^EL9.bjt0IeʝP&ZjpL Mˀ6|lC;|dQA5isu4H/NWXGY. 3Ϡ|s= ed5 }P ŬNИ0_ W(3an9Åk*ru9帻󷞒rkr)_Oa0&mT_E~[ 2B;=@dmdȒutJ?Y&3{yD l:]d >c&s01c moVO-ucDρ !v9hQ[&9y[9@/fk:tif2"E:ћsg/bBS!d WMP ..WSGT%ΦФ]_I}ܛ3"E􇧖URlUΟNΖ8*z'vN7[a+ٖ SoߗS`Vlogt~:^)u^X*j;t.x2GJUE7jzտ}nVlŏ]tfJ^GZ_]5H"-uܕąEDN"LQrH_ػc(Ò[X[eVHebg,XB9HN(! GLUf<2=b^pl;BD`~dlSZNgSvs!D7djBmiBѺY!њˉd6uNLč7d*Bj߶1h,hEfEro.oZ~IPŃ`ԂlRܕ  ׫# U2'Ru ݽm0@aဴ,]j2Re H, }#<~ph~q:U2Liii%bljlm9v.g1@ W2?: Z2 Ъ7|)sT2Pf08Nc px)v+s Q$2^)emޙU5ۇqbE$dtMD0\:YDn-dJY[IޕUU8"2>A cfƐ)E Kb:Bq sW&*9dJ)0r_O%dv _`nO0B|ZhL ZJ Q >sVx'1 d@2#d!LGB 0! B| e|M2! Fpy)#dF!""o#9"Ry!rYBh2t){wo&cLX%\2Bh2)b #"g'j,\2Bh2{Tvwߌ3RǘRĪEWp'9q_ rMBh2 %b =( y+q#]ꁌ kUߒ2@9V &qz cg\҃y( M\}N$!42x6+2&|f% @ȬHȼ !#d>90B&␃ $@J SYAr 4bCKO`[lK/[a/e_7|< &u׺$3y<<H$[7n޼u&IKy$b&EFD"Iun$kݚUyh1G`0AnL;״s,ᆲ 1l)0P7m C ;{4նq] Df^ Bdj[CoUZ1R*BƊtTo0e*{0$2k)XyiU.^ZZln+al]1wU]yWmMH"#H$ϏtG3Df!n4|obp$zW^`-^9G- NTQGה@C!7nu D#2fT*Rw.W+Un 6бLF;^tNd /jV-ۥ._g/'E?-+3.Zvtk߀ծ*[71TnS]e1-B`M|C1G1l/Kq6Ⱥ-CsNJ-eSl+ RGYgtD|\djj1FAy䭃mlCb$AJ IdBb"SM(%bcV,?@tz"EF?|L"oއ"W?dyq"#y!mʢ Nf2k7py¯NU~!N % KDX#PHl^,QsV']&`EN 2ȗ)0R&{QEFP^7 D%xC4یwZf&n _Tt y=%~'g1#?!ia<(e5C"ÊK&#5ctTdEn=\# 7>I"E=v4䫟ΎʣO|>÷Ui-'W?7$~gz88.mDtF M+?eHIl2r!PiP(p3.q 7!*Ӗ"T*}LoٳÖkH6Wxvggه33u$cMLRi1Ƞ6n8zZ Oa))IO! ef sORM#;) 2eJF<ߵl7.W Vvt>fpy A&-`9qwMa; >aLQpw d~OߚXddB^#ݑ6&UCQ6ïؕc)$ #r lrHo e$yP)yDz4}'v![V _oL#7~=s +$FZ.H\5iZ;ևSr,?9sxij vdd:Ǟgc&Sd=¿}|FA GlV-)_j7Yb՘a^\#jQY7ahYhgd`] Q4L.n0Wb!-zcL?Ceе軫o}vo>#VW`HߌNbV)DQ*^EeJ~v 2ίb:-OF5mױ8]Hy0%$Pժ;_phB {= ~{0W"(Y`DƾlddgVtڟθi㥻.@Ŭ̳.I c!;$\7@Wz' 9CH{ 2yd%n M4@HΔ8Gx`L~y*C]9}H?5r{@f|Ȍz/D`&p{LS=j7N#Wh1̂H.p lA@Ղd&@UXphBAa"أg a ;[<]Iyc1488\th|p-='r=R2sYisl1ky c`}w 4  Ai]&CSWAςL1O76xg&IE -}=^)|d(⯤ʎ7+{:Qr<ɼII+w2sWIIJ dNbj LwC7Fق2Y;كQp i;2V+ 2۬ dj.CA=oCUjL*"GA 5@K@B2+[Uj' SASnd60ʾn$ U+DԦ^uZ5m7Hh"lK91A0RcmfoA@Fl9;+$841Ƞ^}scz=}V@YoX3=hudN2TgAƐcc3TtK K|2* 1oy sYl+) Y> 2U1ȬkX2|72οz|ȜKN>{LxjMy\͝ӑ8뗂8:08LEEtCBu Un3Du:4: Z%Wgt<5='Y.WJ %Cz`$fbr$ā5 .)r2Rҫ?9=q>̧Zʉ9qc*^>Yn\'B <}x cu=FU|}Tђ*'n摂 1+=f Wn~98>c4t4ޞnPO]2Qb<4҉TJ(7If]T+AyqE:&|Cܙ 2\7JI[SSes8Ș {2mMcaLmb:UYvЭߴ|uxfOsAP 1\P7ryT]e̫Z2Ѓ슊%V6/hAf<6$۔Hv36G_2{l?-+~le-S%ݡ$("e~A&.sEf\fI(F.ߤncBwV o^34^1]/ya>h.K42B\CedV5E0|,JiX4G(_ .$x&jƎ3esƛli\'>!;ͬt{AK륱323$K)Of}DR)CC>3ΤpVo!Fe9~ck!^/VЏGT2y=(z/0lThg|.jr&̨58れ / }odf 2S(=ReEѪ|6H) 2I CCىQFfKjڤh6W0}Yfb&va\i\#Wlq챘<#.Ztu~JL~B5Z%)@eҲmit W1*?ǒCϨ>ZvON}XԎܵH > %YT91'`&+fsHC3Z>qH A&ᠸt ymW:lA1pWW_+']_>{^ثh3 2I < Hao6zdP@ǔMzOh./g>ӑydC+<4YWׂաm7rAE6d$=Oj!L>xZvem1m#̋rkmra.PzLjP)yv5ւgn{1zdV!̷+CfT( e֕V^2L\\B LU+au1`܅x,Sn,<ԅc[[ 0rd oKph"cܓ}igAF<[5H)$s s^usL23ɟ92er]X8 :M~Q￰aċA,@3|&.HU7ڤ4ًBC#w 2wg ,l>{ASZ֎ ._sy: 2I s: Tz7g ̪>ǩFs`fiE CZ#J9&i=*,h1hrE2[pϲR01Z7_hfDIqײ0|Vk0-[?( ƎWc bLe~=6,p?QQ2Ly#G[a8/83sѿ*wg Ӭ|\WNHw_ze&:SVIӎez̦`Kv'\ 3AN+2 Se{22d].q M 2I C!oTͷ!ҼRފ`|^۶tfG!; b'qB~A*`Mt -uÖ4RuB.^K c=c cIOssdiS>d9~,=;wzG "x#{D}~t/2Go({h |ɏk VB0bD$X"s "vGom83\aWĀGmJ?\dV , U;Ef( !% ;Ud5IEcf釶ܵ9ń@4P^JdVCB[TU'~NKHK%} ^f:?%}:"JEU G'jK@%̼_|;L(nrײYHZPzסY oDdȌC$>w-xˈ n'EmA AW2jԆ_Q#2}̽,22 Ef~ӭ\BÊWUlY"cz ?qւ\dNOIR V -y5"CŹr&(ىF"î\WhD&&sl4ŞVFY2k0nLg+j5P/pTzY{6Q@ɨAfkK5i"3A_ EEF?9^J6>I_BIO84ׯ6U% arơćȣZqcKK@iFd[D̝]{ƹh;~Aaqu,.\29}"qy(2>ѭo\zDD:w"GĪ[ܿTrN_l_Z)qj}):UK QE&So.ƍ8n/_9Bd8Q/xWP6&>Ddb$v %mx"㢮kFdLn>JdzXFӑM.T]r7`̈2>Z"*ne0~} +2iuKd,NHd{#cU-=:9o)Eχ0"bũwWЈtId=o)a&s[5$Q(¥G3$wV3"=zr`P{OVRkwiu InaS%2ngC0dRz劌r[ /3!mZ&"CK@" qRCx]yA3\({\qkƨ[\j/AڡE7)d%f+sS"L(6>Z|`=ΌC?T4㉌jr4'2t|~QsB%|)Fdqޣ&\-& ~ɮrr>ħ) ]_4(2SFEKf1ԒȨsb|eAn,s/-~|u^< nm^[tr^#Z4SIk"5L&L5f@=Geatʝv\K:d7XWۘ"35g F\EFr[aĈ'+ jBP{!-+qH-NBDd"I)% !+~](.Bg"ZqȈ ӯkκa"2tXf$%a6%i _d!"s:Y iAjڸ6][u~Μv`o@&COԕyw f 2\Q_ȬQ"B?f}Jsa[)N|tb(yLDLRk!AvP}J~l7G)IFPAx1B-Eah"CV}oxBwwOjuiI wV|B<={mr^Z4I"644#F]hzcQg&EW|YĜbg2ȡ|%-IV P ,-9v RBx<-@YmSp37>JMп!_#ΌoaQ]9䦸X.}RWI6AJ$T:eb1=_&I}+ }L(6>W22@~9{ uA}8TCǬ Fd*qՏ޺~ײp/# @!Ǐ'BTWj $&S;Z*_!0H]>aĥ + Z3^Zk X\{ɜh*uȘMd9d+ dҤXo͞}]nje kjc#*&WkpBm\l;05CuqnjM ӯc<% bˤdą$$cmJ/s2#7r1ÿ0!bL@ t{_3dQ2fu~n9| ]J!3NYqæWgH\1Z.JnG]{;bgW$u& @hT56o!"dP@Ȍn]pnNiRGYq6dC|8a[xy7OJi>xc}_}5{ݖdnoO&k[J5Ԇ3(aLaU2YNBqZ Ejy2RJ[dAr 6Vr,v6d2j`PXdj~LQV9c5;Y=6 ̴(j痪6ɐ:qcbd@p!W5iO.J 2qBpOĚGlB@p!ױ10Be-DQ,lJ2xN.$ d2&i!9!   OAB'd !2@  H $d|B2@>!   OAB'd !2@  H $d|0+/t_Ú }igs܎~r d2wy7_4}ھ˝Eq}2$ {w8qq+Fhd !a@F.@H8J.RPN}cH.Kegi|-c^l~TaNtî|5d]ˈJ! c?CGB3d~W|kO!XC1!C!rp0!{ c6bK2Drl9tЉIS`]ӂWg>)zhl[7$jE#-8Q.?.W*mϮ!sZP۱%ںu{aT2ym__cb_GExիv6 IrHC6nS&Ku ca쑐qRCf L=b0z#K')l"9tL~^&-4ϜCѿ7`&@,>Z[ e`1êYҙ\c̠$*dw"Яz%^AY ~x wz#c2_CGBVBsZrPQbi^}1zOc:ZF0-#gυX8-d3DqȘݧ.ǵd|WD~w#dD&xU c=׹ rcAaN.1􎷹V3}dKZ;y(R/ vDio mg=i:1!8d{(dgY:CC&_L1?H [0"u B")D:YV}#l)IO=+2K<,>__ȕ6Mv@ 'ok3k[|%dHJ"j!=P鈅Püio66B6aF2=2rq2;>Ŝ(i/7Lh8\aAZ)-:tOH$ifȄt5̲O\'W*ۤ1*d3rfs7duHktDGN{M{wѧ2~ cT،1-2)|P$08 [_OO*ѦOdc"D)iGV}/wByv0-# dS 4̘D8t ٨aܩskn< vtkR3|bڸqg4= c+8d^2=lþ %dt1rIf? s &0C&2PSIV}ލ9c}+dj$)QS>0n۸s욑ycC12~*d32 U,impҥ0YF*fdCnȘfh|CuWc U;#d3cI+dj(MqoYka} c_-v],9dHZcqt7dY3dJ!C)L>ê40#mя4GHa{wW+ԏ2c2a+C8T`E!Cg  }]R` !R_K!s23H>&%EPa ԑ0,#2!S{ EY;6#!%|W;8dc_!W yB7$rVU"d#Laͧ)1bʛ!9keٗBcJK}WS5k İ=gت5L! \BnCe#yoN;QMi:t1! c%dM¢[!C.0tؒ.̊f2s;2A 2-<!C ĹE12Kd}p>">.!Sz;dꏬ25me^D61bq0a D`?vP?Mh2fXt;dhs  kRPg Kt$]8= +2bX枞+Q^cD KjծwB*[{wn =:G !S1g8dSȡ{H'˳ᚾA:(Ύ;{0]cx-ή?2;׷oaC19c 8dc!c?_kqX!|񠁠Ls9{sZNͽuE-D(j1A.1<uڥCo7f|./|}="⣐BFD|2"""/PȈBFDDDW2Oo2:N!#"""׮^TL9Lb `sw3܊بZ:Ddz2"""2 iBI?0$~teBD#L>%1圉!LKPȈȄf2d@==a *l{Ycb9֜&?OPȈdf5dL?d\0!7d\SȈ\BFDDD&3!pEWV9n}dòv`~buce, B&zMa~5K׬G+Kz֮{`Yqv'8 񳛷!"#)dDDDM3d*liZ==c8p&x9b@P D1Y4CĔE\L!#"""Wo! D|$^J4L &Ubsɲ5v*ck!c%w7ƌo2(2DDDrӮfkcR2<{2;QO(2DDDrӞ8ML2.2z=TBqDŐ!""pCfmOhl2d*؃͇̠LΑOJ -dF1 bQ!ө51|z4pj ŋ)2Ed b}Kcꕯw)ukzAxzeӀyc &zzX1ƽm]sȅjGɇДJTi2֪{1TU,W*fCZda`= W;GK)xʸ(2DDDn\Z9um瀬*XІo#GPgK2" eXz{@q&WEXm`⪶uewz:Ii``$bV9WטM*q(#agJ5mL꽲؊I*ndw֕>< nECB 6^G֐^ %gf|C!sW{eү)tLg d2R?L,r~ul2P VjZ>d0- iۤ_̲Le` ^(2DDDjȔq Y C&V@?[ Th̻ip琙F[b0vx"\1%3C悬JA٣V!r 2E!HʔXʢ%en2(EӶ~ÕʰJr߆/v88cą9[R{ݐ,) & 2q 2h 崙 k4c'f72f_][2ԚLe%[7Ⱥo㷖o>֬QIiM~&\5C2|84&ۆLUvBTl2u]A;x"mS7C" \C!EC ]2u!3+FVIFBfvșh4l A@d%jR~LBJ?]ZA#U_"5f% O.dvVeiƜL Be|&d&!2{2CyVV4" lql,B1\%-zY(s'DZ>fK.?da=y!8t!Vq%z! %!s#=:?_zeȣMAVZC$'zȁ(2ٻ&8OH_ڄPE" +bjBXԈ_(xPxDQo. M7y>vfa7QCfR,{eXg8n$y!QnȜZ(̛窵ꐑԡA4rE<uC)e&2^3K(B !Ϧe/t! S.۟!CDDDM 3ڸ)l6놌U:!siM)crx7dlTEcpYQȤ_BH """j^duPM k ɶ +7dq ^~CFtx~ԑQ"yVkeWf~<īFNr 7:$LD>C2Z\p"Q2(lvC&ᩏ>7dB*Ư(1YKBźbz]OxCfA,F=ӯPiW DĐ!""ml$%K!M`2x;dN8釵n Z<029matvUN/nU%7dƌ$@XB2LlW[Rd<i2q%B $ 5-dN:dy&d.Þ8 e_quA&V7d^jq&cT7c0fnjHlmli2dpҮ4$s2v7A*ŜJהtC2m쩚OՄ tݹr|VQ !3g?bN[ś-_NmʨP\/*P+ėeEqjmp"NFB/\yeN \SkQ%. 4 {YDĐ!""fL^ Iq6dtA;6CvM?2R28G臱il3,2I!r2#:F!Sp' & 5+d6>-ڐdֹ!TBtI87dR%rgbB&SLhTW\W^66/F2=UŽ~ YWx.j2*ԇF!;' & 5)drژFE\ڐ{7T ~y3}Zl^ Bw9oBKoh0չbkSg_,/F"2pU!r)eR{a 5!CDDDMu_lCc+Sci501AȞ8%r}J5Bc#JԬonS!CDDD2g:[8ʽ$ɨ2!XZAP """j9BWwrl\ GJSDAŐ!""V m-<,gBYy?gHzS՞t/!CDDD2xY e$v dF)h,C2h{Krhysrw\vJOVlG2DDD*d*{# E`'X9 Y%1t 9[nke]~'2d&d! d!! ! ! ! ! ! ! ! ! ! !,Bh‡Q2}]]2@=d*B2z(B2c=!aQ"'P@Q*\7+h712M'ڰvx/+*!de2@2LǨ;吮fʄL^gG dF uU'dƆicnsxf Lt_}LVOBhU "$ (21> Ш2bB؃EB-- 0S=d1 Ш2g9d"VW7 d ZBX!oQDQJ6(C-i0iYXhc TڀXZBpsaeB$%ly_q d2ZGBh!u d2ZG rlBX,B2@@#d!sR5Bh\!qAn7.ۻ@`8.[>fTU>U5ovq$dn4Uң۴@'dα;P'd sLO8A!KQ1zxo؟s4ߜ5d>~ћWV#7knEW!mBc(&F{??vbzr)/OvJic)^l3/W^dwVErS J' `n2ٻ&0AA "'шZEѡ(:81dPŹ KSIf!K!CvL{}9Ӥ5g3x佻\+dΘVsREV}7j`*7o5~+bUs 2q}9qz  !|ĐF8,z̴hqL7mI!SҾDL^ h_⒎ 2 ]gDǾCZ2e{l7R DB涞_RjOBWX b؂>25Gn*U5SFG9w;b#}eC?\t#d@'dl؎'d164*f&FJ dҪ|uMx!Zqޅ+Ԋ➶*eB؅uȄ$gyռ (dtp< %8ލZh̴uu'ː9+Sjq f+]{]U T6!d@b{2v%{kZ<\n52d*m.Y /fc]^[yy6?-6>ZF`eu+mrg yeeQ0%ң@gJ2 }PcKͯ:ѱ9v)u|m.ܻ`.fLEF.5Wi +2 /!=oI_m(uZs KCTpT*UugL&dRX"ḏ}Ḩhj΋ϴV;BLnHAJ|=d-}WhG5dj(C%dSzȤCkẊt]ckȤ*ˇ[sI`=d4#yGcRrnĬ%d)ɻ9:0t6Lzdڥ Z(֐I5\]bZ)2v HpB~ !eh^o]Ntk(/:אָuGY]b HlCf-lN3VI|2( HBrev.1Bu# [Iw:@uH0g P p'2@%2w"T"܉ P p'2@%2w"T"܉ P p'2@%2w"T"܉ P p'2@%2w"T"܉ P p'2@%2cVQ~W>/3|>BA +ŶS*ksNu94$g_Y2"d#dE[Gȋ5ϓ}OJ@B*'өu_ŗ//?oF n;d>b5Lc:kB d!:өXWMsШ965s@ d搩z:?h.;2oqAf{8l7Xl  o) ^+tt:dZE)g5Pj5k!GeM[94vHgG8D_3l>o*FQ{U櫐)e!sh@ yo @] à= ]"]Kl ~y>ND${'Ւh9w"35^qЍ"2PG{YɺWJw_W3 ORw d2{h~sDO[B&.%R϶#Sha${9jkt\tHrA<^{&Wm 958x-)b20@ ʥX[v4 4.2#,'z9:JhBE@O^^2f:惈웎 dNLɔT};͐$'[Cf&@n<^'ِii4ri]2RϾ#sT2`BڔLKCqblyw!ӖKem<{5+!Ш7dRMz!v)d %L4kΐ PvY^Xr󵧲aޮL}d;2$T-ƻ"% 9C~O\ڐd}iNfNeb:"{b!v)dzڕKaaŠom m (.,?e6dJT'&|6Iei-Ƌi龏_[<ܭjƹ1w @ y2XJz/+OUƎRcy"4JQ~:뚕gY[ݛ1'B\@ȈAp-kYG=?[tmp+U;!."dY3I|9u@l c /rRTG!-ƾ8tÉ̖!-K2p@8; dBu@ vBvD`GdvD`GdvD`GdvD`GdvDbi3-J]n4cd# F12r `d# F12r `d#223ٝvFq[݈]wcEA&ő1ܙ$RtH" Ŭ{ʔ9 POJ """Bfd{QV5tFMeYդtMY]@:I@D """2Bf#$)A0Ԥ驾Y@8U!CĐ!"""!s0dd,N"UQN\_M-zʜ }peE2D """92e^4"Uv}2Dj5詒Et>hl9f1dc y~wϛy}~C5L; FPQS }`1dc1>dF]CwKTr JX5)z}c1d1̹9^ql|k2q|=_C;۠e,I)n&GH=)z}:dz " slƘ\17g&}j|ld_l5z lOCFlB2DDDv!sc^=B\]<{1[sYD*bXV;d2D ?`o-p\AW[%B#qPq(nptga ' Ϊp, -#QqG<$e4顰Xj홗̣Tf42Ȇ"=2d2DDD LKN(k5kxt3)-T~ 4TfT 3:2B-#b2s!N(Md|r;=8P7@Mu_Q!c2d2DDDt^uCf%/a-0iZAY]c8yTm7 ]40#ÌΆLq!C!CDDDT9dą |/Bf'謃B.{O2:NoW6#ÎC,201db![<̫tk+ϧYցm;'mw }baF!c^ 1db!]?t!3e:ȅLw<ࢎjvb$@ǛXpi aFہIp<| 2D """*rxnJi}޻*dRS}p27f44!CDDDU < 7jޏ;4/i/<32̨]xYWDĐ!""~@ `GZ|ltD${ 2$9 2D "@d8" Gd 2دc( *DPX@V (ƶƿr:" PGd 2@D#2# 2@d 2@"'"TE&| 2@Ud U{*2@d,s U 2@SdrWD: طc SI+aRX(h6^A,+!̡r Š66>O9'b(2B(2yB(2ϹB(2< !T YR*z7"2@!sѻ|` xlMfy` xK2B z_D$- v< !2CG !T r' P)d d dr dr ֓޺|lGB_| B>ػ{0 +ڤ(G2)d+/"   CZ56Kb6{ 1+B2@'$@5!1kƆ\!)d}{i 0  DHHT@рz6d|{M(! 2‹f(exk<N2122 1xƆx yB62@ 1dC!  o۲g!L2@L~'TDz3i%d ؽ p      OaPp5-'2Id'z"D p'2Id'z"D p'2Id'z"D p'2Id'z"D p'2Id'z"D~0 fD8 $2@Od=N"D8 $2@Od=N"D8 $2@Od=N"D8 $2@Od=N"D8 $2@Od`kQvsnPWlBZR-D\ b6P\wM wn .0d&&!R33:w8=B%BD`#dX"d@=B%BD`#dX"d@.M-C"dri㊄L#3 =  9d3Byqw'jȟ 65fHB2㥪6؆L/kJF. ; 3dNrB7QYK]jab!dkhLoh-%]|VcEx]BB2n;TRCF -C!! z3b8ټ2IlN 2̰ŷZ 9<#M2m!3wc췝ddM=󵫮Ɛ⻹]8tƓ]c-dn>d  ai(Q!TQ_9d̨z gBfY_BF{e|~Ƽlwg՘i ucm4#zFkqS5zu ]ԉrBf2A:_2j-_:W @~wMq?TAkjkZMDɉCQ1jhbI Pp(:ti:8BG(].&3 }&z dFa߇* UG0[jtA<"CA!*/)2b۵(,Đ!""z d/NTjbn(7dSswsB%QcR>7wh>wn!dJ$6[ """ Ch7,d]TaWCfFT55eH!2Z*OS-!3/js*^,"CB끐9)j3ij lAc0f –52?E|ZC?z !""=dފǢPnrۢuCO|=(d"cAȔD "S1Q8 """ B抨<,Q'42}f 1&EBfKTw?dsg6I@TV{rr6" !CDDD@ȜcmRȉs~k~.7dxh:vQq tT)gfC+O-\{( +!ܘ̿ܛE.]#C!`,1CCt:CB`ѡ2 AD2DٯCA[? 'z"D p'2Id'z"D p'2Id'z"D p'2Id'z"D p'2Id'z"D i" 8w A)Gr51,ZVVB j0i@Q 088  be^Ahk3~ͽI2"""R BFDDDO!#"URȈH)dDJ ?TI!#"""*)dDDDN2alME"8H "SȈHmC=>:M2:ы5D?< D2"""RӐ ~aYB!309\9_1K3dѸ)s?aȼk3 `c2d!|1ts"zL< kcNB&2"C!#"""5 q2eW2 2#̤g(X lc5v2#d%F#CP 3B'J: K42xے'вMLC`a|](dL]l({r{=pJ: јþz^d{!OQ!"L[ZA[-d|֗K󴦯3*K|C}vE4`ck|=0,挵_vVyj!(2"""RyEEn$ͯ1.Nz!ÝCбC}ɋYN5{!3IRc}msgN Sa23hΆNuہ4nRʅߘWy˽a̪Lb[& 1=( lki ].*4%8ӁxtiC&aEW2tȟ` ~By&ݙs rtEw8yU~̈oGm䅹݉͞=21 ;!9cbo"ni ]Ȝ%PaAX t€u S(E9{(d2ʐHp XHeȜ.]T lVXfvsEluzBh5+e 4 .d^80D_V23cP{X2=dֲ= [!bR2`M0U2׍ +k20gN萉sż7[Yڅu.*<)[$1Σ,cOP/ d2b!6dZ!Q2<>[ j,W}L3?j=6fH}4M_!c{k6M4r 4q;Qn1?6mRυ`h6LC3P )<ɛE(}?_7[ rF{?.vړW5/d"%Ա4W@e7Q1=md2CC/HEI!s ƪu˲ /ϡTАQJ)TB&DN0|^^.WlFc!LToZ$񫱱@Cȥq;0" 2W`$DDw$ߞLC֡!RJ 3 *qƆ#C'dr@U!3FqDVPf̙] !ǝLp,x\5d2fǴl̚E YG^6T ѐQJ)TC&g29`ǒ9Te 2CA 9 CŢ9˨&~7d"4!M2~g",BŽU 8,D21}ӄؓU(B4dRJ)Đ#/G@D`5dSn{$,>RҜZQ*OZl4dBOṙ{8!3avqyDo{&dҐmׇ}aR˓9 `Cd$ vfMv_xls*@̄z#=YÑPh(R!$ErY/\cdrV]2!9OZh4d#aSQ27\e YA>GYv9 4*HY<_k" |p_}HY EL\HeWDT+ѐQJ)TSC]#3,NewIZ\$C8 Ih0dl_ „̘g{w2; л92qLtg~AH.݋TO˗ݴ|+5!&꓈X8tYvPh(Ry!c|8*ێnf2^[q|8==du`v^l!~ġTKѐQJ)_ ;2 'd$D"P'ul oo,,v9d&` va(ZXx 2D?o@-"L*<֦w@-"̥>q^[@1"̡rD DHGd@dtD ]w:8&>!L: -?PO QPB2"Lܚ \nũѡ,J0>x'2@v d@2#d!dGBȎ ! ;B2@v d@2#dRZ\ҍG Щ{Bofq34XL{8r5Z|{_5@%dJ'eBm:) F^FW?f3GKBRJ3wL̿ MEV*Eq2ߋ;52S,+2. Xm)^6d2SX-BfQTTiX @M]2S2u-!s83@B8%!SMkv^WD𯐹Tc륈[{ۋڮlߏSH<>{u0-s'/+j5~܋/Գh,Vz~sǮMqjĂKҚ&1iXk* % A* dq:覃t Q&%Ui)g}eW2"""Es?2x MtRx!sB&Nrꌳ\4YQHD2tk5^d}(dDDD勐yFcToO qt@rU y?ITK{˩+'d/ά5W̶\AϘG˺];wv "/BgG$Y )i 54!3\ 3Ap-O ͣ)Rd  hM>֔,_\$gC&zE"!r[4qQ B1L?k h B&DKEN8ɚ20ƙs#H:@tL4泛Ct!dCb;)Ri` 9!SS8n#B.ոoSӂBuo/-M"/B9-~X \nneɣrm'/Ø!Yr6$ &d&CT/CfxkG8YSlsv>Nd(iGx!3zp(iY~ $r6ɩ0$!xFdqi7J%H\e/CigIV2? l2 y^Ax!>˲>h^ 28ȦPW@=@z^Z;̂] mKWbi _ek1#iJ'd0YzqDD!#""" 0|H4nO"tGdeA_*f1%0DD!#"""~ BFD/ QȈ?G!#"": u;}!" 2" 2" 2" 2" 2" 2" 2" 2" 2" ~vD`GdvD`GdvD`GdvD`GdvD`GdvD`GdvD`GdvD`GdvD`GdدA_##2;" #2;" #2;" #2;" #2;" #2;" #2;" #2;" #2;" #2;dp$X\k3i2T|ؤ J, _ ԃNCf5:G>{bgx~=|yol dB2Z!- CB@!d@;LRi3/! |vThLǍ &PȨT2ޔfzcM2 u-jq=j2@!d@R[45Xoq7Tu{-dbh^ H(dۭd&lu_oq^~0$n!;@"d@"!^2)L!B$2%3$d2 q)]/i(?YFȃOLod;gN:72b+ +3i9g4}r:+3(2a2%h>ު1 ֤V,Vm"vx(/Ը$F2MOڰˬ쒮:fJѾ\"+-;X8 d@Ú5dLF/9dZ;d>5rN{fֶV:B4YC^jʨ-3אY?2gCWˉ-U8ВpA5k)GqLxKv9`j!)xy!;1˃n^pqPvu "d@Ú8dK-sj̛^ײ(d CfgTdhE!S}b_xD`GoTt;-!a]? >b뢶jm-Q?QQ(*F+EdQ CpN!fs|޻Ki= drVܐJ"k@M2!CfR`YMc+dY3ֵ BVQ顺,fDʹ_|!S?)UufB橚%\Ԭ>"r d@n>̄Yj6!3'2I'#\S\|%|2 †Lj^0.ZW&dJ쑚}^!HӦDF]FrcD܊2:7Mِu5Bi,tSk\x!d@n ~#5Bު 5D>3Qd]wicY"TIu^ ȭh!1rCMl9*F$5+GS/Qc :}kYzn56UG!#d@n ]j%qBM]]$&ϐtxI*$dRo%S3>>`chX_eڮɟƻ&&&$i| LMMJJJ788vvvlll剉BBBYZ["""oopGUiiii444WWXQQQzzzEEEddesss:::GHH2ubbbZ/ -***i\\],,,{|~噙SSTŹ蔕n}___.//O};<Er("8W{4&Ukzn(2>cAq~ / @nE )[ @nXP֜uɷǧtXj\G2RDr/#E6&e%yms%%*zѤ,_@ `U7!HFz/Few[+)Uuna;.GZpW#,W'E `%dZ0gO7zcm:tHA,ԙĵ3%'t UR!pܭCPsTb#6ɳ\ 3Α!1>82I PIelf)X -ZJoQN`,JFCN3Z FG6Kт Pq9NjqZ c@F: r)=H SU,nF)Y oA.!؃0Fkɴ6J#z'5=}>\Wt0i,#)i  S 7NO#`8^s1wT>G ` E f 6~%YJ*L0\ 繮U >g<"&)a Fg-Fz􊸲H\蹗] )?i0 x0Z^KdmN[5tv[ZXufsS`U,x;l!z/x^ G/ o6]vˇ%%˓tk槂pP C)ɷ=4tY a,=dY jV,`OPbS)hVpx?db>D,xl?,aogKw -A%(H(f/lFJAbXڅvRv >o" R]띂%%H}7gi TUUlI 80X,ŲL;6G!A8!bz_&3| 4BS_< Am [D}8{Tę,[%i T%<(,IIx{ LLwi!E-w WG lL nQAO-?4.'lւiཀྵY] NJ8%-qT72Ņ%!U0d_%F:hb,UKA7"HEĕ>+3fqA^D&(R0XFJCz5}s_62ߛUݠ)OP gm P07\u^"u2JmuPNQ< S`isU;҈0p w@}z&'O@rRsOކ2&_I&'77%#vȱG,7XᇅԆ}5=“'33O"{%_!̕`-X f hjcHAؓMI]?RB:^݄9*傂 IBk &r쑆I UI(k!( >DJG^ <!nF fxy  "׆M3Y%sZ<Q}^UM_C5c}n*RpEDŽՐ )%MG#Sd%!_h{զvD`4Jnor ڊCcs!:-caX4HWcP7),)A[B j-xC'4_<^GR T)A-(T\PW>2[OAJA ;>hҚ#9h 1ߟ!N/LOh)xgh ʥYj7 r&JL ndzxf`m[!$ O'u`g(8+^⇜w|a$`v|!c)`o(KRPwɭ1-;p[3CB c߭q^&t]/gN`ʹIC tj/O".ݡn3BHr`06d ڡRTfqUOAˊQm* rQYUT ) qG+`I ,OM]%ȈAdSBr)-80+g- *ગ܏eCCiM5J.!D'*dRP8LЕE2ꖒrPFo~#vԂvs4>~?"f79}ێtSQ/!gCČ2D`HA] ]5.BH!Xt)h50)s;e+!`2 A)(T{XZTt/U,.THA\s>$&w❐zc m˶Y$EǓBi J)%)g|ܽa0“퓂 HYKl,8LV-H+g۔)}ү_PWM`?ʃ'{)rȹ-eUB#)WeSЁ{{046Gˉ=g}]goxp]1i^Qq(I=P<> v\۔L]!*uo<>d f[Z D?0mt?bzt‹ޫ%'Lqۨ *2 8@G+]}k|6+_& 1AD4ͥEGOO+RǕJF?wPA6[`?b}XTnmnb!7#vQA7bR&t\GѺB1i{b. G-HQvSY)\]ꪠT0r<@J_,ETE1".tyڴ7D B(X01 ?rmɋ8ģ DByeJl;ωzY;9 R@385 6Bl&&hhNṓ ƨ '酤?_ggrK*88믧ڈ6E6Af^q0b*`+UC3sj!v*``TH5nZ=POu*@K/w "L^ACCq , "$Bk;ëA›Ͽbdžγ $HfP܉DZMWnUzNP߈Q5ƙ&C%1<4#ʪ S~ZA]i".*JV$m(K>?mZPONWA0(kKj6*;$TYT{< EmYzFTP"f *x[LPA柋Ӣ?\^W^.T rW_-STpESUqDdULm`|q]2"z^؍,b6`d)庘wmZkT7ʷ] Ǭs)?/,&kfiA`)*R.زH2t]6l؍*3~qLrWl0kL{x`fG\RL<^TpKNNϷn)Wf7`*x(X&8`PG:x\F(F"DK }~sr)q|y~CRzȧ_]U]0A.xadeVd^K@YUA8HSAY b]_aMJ^Z?6-5*x(+Mp* NQFT!`0+7Qr@.UӬ>PRQ_co$X z"3X" **&lNU3C' UCUUp Z&EQqRX?^>r Xo*2ۊ#,TP7{TpJ[$ Dpd2D{e]Y0;Q0\ ܤ7ApV=\ۨtA'(k϶ש 0MY@bR}Wݞ}":`JI}a!7Q)<[54 *#WyVOT9ktl'4d?vX"zф1*(Td;}( =v.{s hVCrGi*_%dO>N8X"2x&n[XP *XQQl No'THAhFDarT# +Ҏғ8>*)*xϱ lO\Q9*GӬ][i])|tAռlFtq{*x{dH M; +iݨۋ[kUpqHI]ԍ, ڒq3t*SXr)9Û<;f`3PHuARiPA|c9F W3FH߂H&A;ld^gt!Ys)x~)>cЛf"mi,Y`\{e[11UP ҈v[~1(D/URXƲ*X]ڱZ~ lp+6A8hF2*R*(je>As֩0sd {M;>3͕PAhb:q >BMtOm;T?I 1'HآDCp_1yo" 1U)5J[5;A%õb Fi7IUù/ͨ Ni FU@%R>C?tVܺ r;m a+fxDQ5GdF9xVJߙNЮ CЦA[,U9#[A+Ҳٟ:딼Tĝ;q6dבt,'XEr >’~%Za:yc٨  5*8d zdsBx矽dߕJgvӋ3 iiyAw}?ov,I'II *("ͬe+1F|z =]5U7lk*h j|Цո^;K,n8, SCCC)"oa5 K.;D*i@(&:Qjkf)K.󄽶F : Dٻ8>- 3y9i9"̡r(n]Sr ̝HB((7SV)wn\>` {Rsi7*(EStfb(9ѳur(L ƒgSSM#,p,&_MAG :L" <ԭw_S;0\RTJbq\4Kc3)ZQG>q G6\[ԉ3V;7(r&T_%0*@mF \L?c#|IbP&40GTQW"u&i#Y l)T]yGIA6N1IEs[l\߉DOv:}" gV͚L8T&r!5)ZCx)d#㩺o|d3IA6f5}!n\b*vZÂi)A?}zi}Eo!Ԑ$.(Xg_֣b^!cZ ;z_8 M1L~ r`mlޖK *d̼riL4$w^vf(t HgDv*Cd`{#&7mJ퍩d]~yǑr& kL kn,[9 qN#HAO MܮDj8AӒ6g噤 qX)Sr R_ ,Y;,EH?HO{+z bNJ4P)%*`ߡnQ?Lo{oPMlvLmۖIjiAs5 { Ɠ+e/,X)rev+ʨE!NASMK |u@;TK'c Yc'ϛ!'u3Q]l%ک<4s)JShM |~Jah!"@Qi~[*D…YXBd$ZhѕJLS)_ra$Ps⩎\'j߾㚂YH4J>~~/1&Tك1MƘ쪮`gagi(ME(wS;/bV ږHJE? ]Hz [T\m[Ɉ1ѫf}NAKA,4.2)X}PJu^򦥳^SFkv/a^v0  !5&<ɤrl"F0Dbx 8 ]pa$fB^+a.Kk)"([ CDDDS5(]rgOSЗ؎RâNޞEqDvPi e SvapgS,UYh?K )X)8f ѯԳ!X ݇NLڰP[jR>\>0bʺP>y ER4* Fբ˙1:!}3ddLV`jrif%rW'BDDDjL^ȚJB h؁ Z=͐T}Yw0%sLQH NHBnARk2RPGR#m1Bs(#!"""ZQוue"]1>: L]Y<z-rU?cbe]Ơ% 8ޠqUA\K 0W`7 Wʻ`5mT]pJZ"""U58 (O QZ\K+؀eo2U‰lnWj9f` {7N{'i>k}LA^-R`j >.xg$[Ã_3єsK%TR0s6`先(R%i`\F5LdY(u˃bL)8*g7 3GmWuDDDupH*C)?i9NK"Fą,5O1/<m٠WJ=+[`8cn)9j+DDDDKJk܏𾄜}+9H8 *S6T s8;S1,$2wl!ynKS0X wm„|Ršjʢ(.V )Lkp]%_VpַJ:RP Oh$?40ꖔNJ)(? "Q0,(A JA)ydB |1)Xnc<1~ҴROvm'( a i1$fPhǦ"BFDքؤm/J x'u6{Zb]lG'q?*0cXЅvN-7Q0Hql8kc16SwXjhtEzT}\MNqd1^3W˘*\(xИ*qd1؟~Kah`p ]{_[(c?-$Y 6e`,,\CP׾wQ1cz$ GqF3, fpf c16뇭Qr#d%HVإ:Q[/%+T4K+qHz)p}ک2yH+%Y)qm{qmi3k *d;ള 2cn@2cK̄d8;#}jpĈޝ}nh^E_h4:5M8%[ d N4GߴgPQ#5[čHjnEKkWx LE _ĆU#NH-,wbSg7X?j^qǠQkOݫTeWmCwhbz$MT|Cxѿ䩱ǴcDc[qPgl vD{>WlSVYpwGM*f*jES-7dA]5dcOm<)D=WߠAU~TS՞ZȻ+R&V Uz~QЊW`]O(펂&Q:# CJN(@ lM~O˂* >Ha0N 36+.ț`Qbbl44^hU?C?m38 %n;Œ?8@ &j~-JmK@s @jƭahSCh|EB:smw6e/D4!>|ܞ(ׯ Uv'=ౌ.vd!)1G ˹heі(4Qn847a,Z+K3i`"2hʮEC.Ws HjlP]鳜[J(1UP%gY&*Xg{7YC"^ K`#/gkX{MN)dl[c/`y 9ܗ&y2hN}<~¤8~_Ew8+{scQm cAM{܊ѐ&Ob}-P<ڶ+ְуf}KäLpT)Br~ _;DGFUUc T^w$砆vx7MP}/f }YRcЂ0ɰ ׬ ]|m[%huPA0bwZ8' 6_֕oCY+P Sx- Yrv2/s/o4hK8(;{\|h >} 5l&y֊äLpT)Brʪ :tC`o^491?[aq',9A|o홱 1Uk߳# n*Y`[I-<Rr<5lBUTr ՑJH3ծV}jIO^CR0%$^?*x?kbϲ-Q{G?gagOceLP߳[4k}ܟeE{8|UCֳ=<<@ d3%vNRݬMR=]@y8jd[O8ѼM8J<@SgC/GJ- ȋ$ YN˞Jl3rN}wF(,ACGjrw1vYƢ ^)\*.ְуP5.A%IQd!9S>hb«C1It̫^%\4̻ ( 7ݫ*5c0)<_,a*1֮X\30fc񽪠l ^a:;L)(OW)~ğxt,i +@iJ)oopR*9JUL .le7Ed!͋y:a[~AF[BPA6Nvk*H~Eӑvf~5 Wxx*DK9Wac jحZ<0)?#32,$g]YY {«t(&eH( .GdUp8b!R1m‹R -wж8o[Zvlp mr鉑 ~I+8̬h):z [b cPw!*9LLL$ ə*+ۧ͹/$#vG8?NCn13 ?)>J=bI* 3z|`f^x]|@cٞÔAtk~+htT9L_Oױ`$ J] z<*8v|}.|nʔ)SL&DFÚhjCأ iڴ Up/)SL2e:S,VQ_1@DQ4`b.Pƾmem]ڔf?‹ JYLoMA<p%S.[yiLc 2ps 8T=[yd >s%pSwZ^}[zlAc :n*\7Up~ҧ5R^7p.gZZSpԆ)ps 8T])؊ĸ37p.o5 ^#-LAMKn)8GZ܇ 8M5&~S [La7p.jLI SlڸՂ귱mO@q~㱙M(TLKkڮyTJ TK TK TK TK TK TK T_L1N0aVBjc3p,zA ߊ( Cs觿bd#<<І=)࿈wW)8m\S~HTb裻FSa %P!"_I.bw sqR}"SЄ1+J(P!"Ј爩$#JXL&-/K@USp9 c YNQ2F 4d9pv^ 4c C" @C %),)HAfIA@ 4K yeRM |8q: n9+sւRE ]7-P/ǫ^/ Na   ͯ`·*_)xYZVa V1 ~%~f  ٻ8]PX]ju*R`sź2aACCai {dRk\ZƤi;?C_ J-~A&l z7(RN O ǘ )xn(yC4GS۸)E T-zQ=Sn%idM )p&Һpb).I $ R'ULKIF{ )`OdY#J)p/`q)`'e,vaAd%r:;|䄁`]SP‮ %@], ]eO KGDھmm} 1d޹q@Z"!{90mƀ0$`ɂ!nsaTR)U@ ;f[ mC"agfwOsJ&Mʀ`p? 6{)8 0O";ABTp\=VYTV<4=x`F Y? A8`\[!*PӎFrqvm࿥:U &;OI 6i90K ߤSS? Lc*ܠǫo4_mSĿݧ_!QI!"f[N@b3Y4n; 2T b%j_W Kqma-͵Fw|TJ./yӇOU}1+tL׏٭`Dt}?g\K>;+x*g>ΔB?+?FT۠Fఔr WVxoT&Mءp|T4cͶO܀TA_!*D6)V=w@㹜 \'p2Sw)PKŸVAH ^[hsI=Mޜ,SȵJ΍A.BSAX5a b/冔;BmphcUP-$?ߚ"ku:թX[4ё*(Y¿1Ѧ ~gU0TPwA_+q$~ 1~/n*XǮJES<}Ly $;m.oJ &ǎar*_>p\-~;xgZu0,n#~^6k 7ޣ1Q?W^j*cXc}g8dIk"qty kr%/i&gRG׬zΟ)wd *n.romR{ vyN~{ΆM{rjbqruY@xQz*(O hk]P^|;`z+ vD %/ço>4Vk>xÕ(%:;d„'/Ft7  jMdT^dcD]jhؤilBU al`&$tPnUDjLٷT47Mڨ/iES'!*KdXo0ܦ K4cF鬱 L?%Lsզfr'1:!d3;\`86*o7ߣ1!z rsHbac 9Y^7=*؂Ë 8n"( u`u_Qo202Do6]%-ʰ4pR= Øt5n/iX pJ 008VTqN ]`y쩡3D qo4+͍c='kfBMٲ'!쟙@8O =#βǻq<^ѣ.+=$8Zh}n稂ST' vpAgq;xw'~յW`pC#SAiz\4PAW"Ax!\e bKR8`}*+%`h4{䳩 ,T[x< Fۗ5!#2TZi 9pg01>a̛U07pAhwqL~&[1 r^  f;E<~gE=FD0NF FdU*όF;@Pvݪ`٧GBS4qCRAWA_$UpA4u=LCDmQZbXmmLQC:Çj0x/T|q2D~?|f9+>P9~\42住{T׸{;\pM!r-hMTc-Uh4RY 8u vr ',װ`m|is ܻp|+U5j * q+;dpv4 U0 ZrĴME=8 M^ɠ"/jmj*E}Myc^-ZVTP,-OTM9Kӵ!~b}&- 5X/3^·Ǩ0Qw&:Wrey֣)2̱Ayhwv70N*ؤ0`ѐp!GtoTIUG4ɬlc(tG[%(+q50TРRA}m Q=< Cn;Lm}6L3lp;A lp8|MNN2J r-0~.? T0foM.ܧ>^uɧx)?[a7?n׼.dǥ@+;X+Er7*h,엒 ZYcd=<TpZƇM3V?)+*}j MmQi-ZkVT Hh#g\|-TG3jRW01*'>H0*f ,dY-:!@iSdSf0&MP XgTiQaFVSW'.NUm Y,**8SER܀bťa*q> @׿Ny)5YXL"QeY'mF=5#I G (o%gݤ#=R@ฃXf0nGpԮ~^so@ {䭪(@+Z]IcNUnLd[PWpM-+a{KϊvTtޣzOx-Ҷh}[3SA}=O?Z*(c0P%עOǨ`*M:`/Qa̱] Tp_&M.UBe}V꿯s*C0Y!NV7|M2MH[ͳTM4"[eNaa*áAO:A>ActFȉ˯p$'] **PAS/{ʥb$Ѻ >@B p^*<|))]` Dx|a kn hh*Xnl%'~13MU۷ c VAOt!TҲ= z,Wl6l86jZe-Ҷh}[RA}N8 MYMrVP>9x*5Vh<Y EGd}Iyj,RTpa41T&MyAVE%"*k瀱HApVPzA?@ Ue#=iޱA (tkҠa*áAOmDWA5j lp?8bx([JgLX:@D&V .T\;? `k B}*6(D+@S2YĻ*GcP^cTBXTU0 aPSAaZZSA-Ri[[>ٜ͢+6ڀ5QGidjj?zNF>Y3WG|J3'A'Tp(;9_pLb oT+P%cI˗KQA}q\ X&MQ5  ZLj*؇?1*nb 18 *ji ~>߇">w>A^F*h F`Յ*ye\WAȂ;MHڢo-JSt/S{guNGZ<,lȩkRF&N `B(ARE@U Ћ>KD "zٝݱxk`nw> :b[_#fs{כ?[O>sZWk.|<|*+2]ԿMz Y;W y *N \O2_$:j3A][0'=TPpgmh凉 }"DAD, t.i pN%SgnYT*wT\ bqh" ]}NCAOH)8+$<(F `}O n {\&?TAL>, 3{k* p~IJ rcˡ9^EьHco1JI#F8iֺ-pcxz䨂\+%/J~ @|g{@ |^ X' ! ;?Ms  ~*"TPpge^7MGldԪ:!WY'̫5> *l+EalLaAle+ 2`<-g B'D?B:+sw p3o<'s0"e+ b۫`zMtD륶W_IQx3)l+~U+xN 2o66o2Ul(ZF&BvdGs4êX5 *Hoo U3N!8 /,ϫZY< m< B`leDEi9yh7H0Uw=Y I&LABĕ  CI HjmU`' crƣichiAag!*[@㱳 >ePlTV0DyJ|Ux&[~S[C9`,*iTf2:sT=).PLP뒎*ỳЯ &A&0-c!+ &ұHKco!Je# &(6@Ms$c9fgG9Ё8 3bKxX+B$) ZpA]ne(3Z}%Bsd|>ޑeU%%:W7. w0(>7(J-,TPBP|esČ'^~]w4zpY @F]X<.Vﻒc Bqn"1\q ./sНطca ,C0p:0FB)ԆXI;]8C&)\ NW!x:S344I lI9^YכxeN\,8e)-x+eSmPKnZ))!J\g]pꌂ,x(p M` )`}e%L Q *k 6yU /%T 8oͣwCS0%&%)ҢFJJ@ TJ#`ߤ A 0gb @ dIA@ dIA@ dIA@ dIA@ dIA@ dIA@ dIA@ dIA@ dIA@ dIA/#)% J R K R K R K R K R K R K R K R K R K R K R;F(&RC-ےm@*VKH'C 0}L:_bߖ͍E?연^..]̽{ξr , ð 2 , ð 2 , ð 2 , ð 2}P_lJYF|fDcQ*ԅ?X/J񈮅yNadUyN֮ݶJ`^l.J]t]L4+/~.0F>N: dkq'Ǐ0A 2'E /\5'dgŶ+ܤ D% i z*):3 2/OG!Ue U75{*BC>*8 ^Sb `7b1VA 2TPۥ@X>SìK*hŃL4NԴ*f)'N)7/(Ձz)*-lMoYY )#f4ٺY M;Q'QLeL5 `QP:^We+XRZe#+e(]ZO&q䏪&stxIynIJ22w9#SƽГ j9 2 2A 2} *h@2GOV c*Vi'-Υͫ $7vshڃ !llZs6X$ͅRVR稌&WlNUpZx,uR.Z8Tpq'NrD*$*cα>GVf?ZG3zVA&SA U#ZU,U0Zu&S|ڶ &X%).G"1+j%]5bĚ9SH@bqQ Zfϊ0M;kAM']d E><ZӰ&Y /<*̹XKVJhe/i4ݝ`ɥTL$RhE.'\UĊYoΔQz%(30n >:="*j!}V1*$N#UeRy%'V :*#h?i뷃cGeϺ}sP&R0C*hB7=۩ U#ZinDvI۩TH]NW`ʴiꠂEc^%l9b>,UpA)9J.$b &%Z;8h,6֩~}.\x sP%& Hf{%NMe ;N u{笨uP fpUܨM[C U+ZbLg6%!S,Ri`+T&2Ei>T!P@&DHK'Mh̥Lh>'sږNb >KdrZKw)&S:ZE|xBe;(LD``n*xχo ~'ČVAhܲ=SA mx$tj\6i9!$'6PqT*y nU0t !os2z"{S$αVS%נUϺsfP"mЫ ߨۨ߆a.*4 gE`g6VS H [P+]T=7bUR5l 5/"*-Cy8c${SJz'ɮƯ=ىpim!6eoo<7~i~rT ?OZizO@⍇'S@XKkv-n^TgkۗI^Yܾ6*.EqI344ۿO]wv޿:/sEih]T%(-߽{-=,v۵$ VAi"88-@gL ZQvQ&ZmiZc\h)࢘v1!#} st@mU7糰s,@R`ۜql rwxwM[n."0f 6UsNYqzevgv!܎AQw[ r<{7DtR`w)~=C4shoT Dϐ)QI e ƿNW`XN()>X[ek 4RJ f촺%G(kI$:cɟ{ uÂBn+춻Aڇuj|9M#YALDs`Ѫ9r@aB9jՇ&O4*D)2 L)(%8I=C'J(~`A*FJ#eܤEci:<&G##iLJ z~k!L$˄H^ ^p!|'9 JIZTh *96]% 6BFb]%\\KJ&d#*`.´<_'"pER>;=^ qDHETSP)Rj)(rA휛`N˰d7kDQ DY%ºwe+W>rR jLȻLj#I2'#hX<6S%d$z"*]!zg䤉Spg,QuR-)@p`K/X&qu*BΟ=)TJ)5]Ng*6&Ǖ&(ʖn]<;YhyߩIfƑ1(a,xUq*-/MIb#(H ~ C<&U!<# PJ+)X C}#=:)N<"6_4y){րk2 5U?J)4bn}ӱӲGj|[ :\vaQHMʺa)\ %34S#)Hcٗ楠Ha(q?esGSP)ԠRPIG&֌ֱ!e|Aönll4䴷Zvw4;1דRxk$blk=bS3pт=B ׭s)8F}oڄGSP)R$jWZ'=QAn7"=-S@'F?;,#kzk .gO m3U T{&]22WD3H\ t ;v1VTJ)5U(Yn,9u&C8MN,[+e/zQea+ؖ}Ф;k%1D_Sp)ؙ g^\c/iT `أgRPn5DR!k75U?J)58e.^5]1cđ4 {- WwB75  ףQyan5a7<v/)"~)HC M8=˿,_@z6i!YTh *c#8+ #36;?¶9d:6M Xob%Eg 8Y 4UThΜAp E;?^5aѤ[{Dt6)2 g<,T}i ?1j@aR-Y2lri {TYLH'!wIP+6qf$<$T3ouY=n'6 o|iC]rוdȻ#ȗTW>C ]|ՅlJNA[~O& bD #?ZrE)"'۶[9F[ ("SOT'5;m9 GRiRLkRSpM Yk @ GƤ`&2;*N|@ Jb2LAb0v@.l N1(0%9 Ԃ27E ʾ5)֖ZPfSN b)Y%8yA} Z9/(Ҵ !,EB & X} jke>UJ{@#'])Ρc}HW' 87?`aјBOlдZ5 czhL@f L_};}/ehUL&`*rؔm45r  Yk/C Lw3R38/S)ir}6T !#a3)xkX "aT HAn1ƻ+ŋW)ݝ$wRptѴ4hkl +A ^-A t~t1j B! e#̧)V=w 6̼-uSn9XHA@nHAqMCdC?鯲9`QS00RnB 7 8AS<@HAR)0[X4!& hO1Ũ{-C)~!/ELz+a?E\4vfe}᯳,lHCĢ{K`)8R`,i2)F»<,d<8vO8n{t:8'O ǗfqIdaq兮*k{J?j_7<`A`JiK{(xWAw_ƃ`Nzrh+Uޚ(RKQ/Q8Mi~,ߚٙ\~S0 [V va<aRN0+>nMz1 dL 1~ [MOS_73UpZ5+ƌ?ѼE\E41, ="lA0*c1f&p. ͙F&bB‰4bʀ%nJ"VP/$`^gnqCX療Jrs:$l(܍YM\$K X4(߂`@VnWaX j4/'WG5AC#cq%Ã޿ρdzGw# GGP.[Dt bb,¥D. 9$("11[.&p?I-{q[&a.3vN6>/!p hC7ǽZ TR\ĸ?.ؾ 1HL{6%TPr Z5 Rd4+W"G!m_.RAE18t/]#w>FОXӑw3oYRq¾.馕F('T0' NG8cD䚵P2L*'lR@^FzP`Edy>%Lpr4dH;ccO1TݶD^ߠUPJ^LЧs+;yt~7'o59uooǧPx <]P2A~Q ; 7*ZմGkys{.F4La_Zdtd;f1+2ilwn$0qEӠ+b|}d9.nI_W8 j4WVVZ˝rkDK,y :Hy~*h"@6q.m#LӃ"xBCowN`t0͂_6ik&{t P[՚' 0M,굂UP"u߹2]Ú+ u*Svt~XwQ7-bCvI0Iq xwn &>K8Z{I`޵Z؆sa=>Uʏ\u?I& F*~Q!c~X]2Rv-I"Y/u(G` c|^YM "!74_X'TyTBtqYUhfRmo\cM3R'{x j8-VK*\>d[i4o'WU_Qu޳[AJ=]ۆZ!#I5R(n[cEqUTxe┼4y vƉ;˽ &Hd΀ܦC 3 ,`HJ{ʭo^ѶT#UД,ۊn{kv-vJJV0F]šu'cF u@T#>~+g&YW+:@#@ S$\XܢCd2x_QAIqa2  ؠBs)Lwaf,M6Cl26Q "2ݔPbo(lU`VM gȧ2G&fSL!y.P}W5ޔ]EYm6$ *c }Tl'YrZlsNFyc*hWQm:oD.]Oqkh0%mr 9GE1PPC*È[B HK̔1O)n"3MU w(v<: C(T2#N1UPv,mnGVNg341ӊLsVjd9LH N`~Kf ci%+N@CٽX. ?ƮVK*h47ҏi:XwZXKl 6?Nē9!1?<(&Ya#a@ff8|ĭgqmc l -0b nhq8%lҿo/G?K'm-*8qpHj HE+&.:aӖ5a+V- ^VAFѼ!~owgx-n89~Y|o7 @"BDgHBa$o"2.p4OݛBbI't2ۆ|5#;hLsgL͝ v)!E ~ TA/N`< g 2N&zѼoHuhV&QVq= Xk'&>ew`* Ք,[P8IM4Vh(§ сk0oK+3HiFy#*\d0 SB@(*¿"[toq~Cki`ԕ-)q\DJ30uN=5`D DR$ C"@!wvS& .{ * ?xn:_9)OA.Hatم0gpƣ'py-ǺsIre2SwH=lg޽>y4RnR0~x()vh d &`9[ρ|SJ֠;uzc.za6%V Y+s0\6cxUUĠٕ[pyV 3u ߟbcq^'~2hOZ)}$0"Ipd t`4OJ9HAfTk}^ PPRQ%vC\WgNPө,Jv 虂l&-E[U7H I1 A:eN8q0s˺6.i% EMDLjzBt% R2P9}<8m7%w i#}vnR+1Ig*uK tS0W:?h?a[ RZ% bv+q(~S WY68=wuOA%L7NND0!9Nv0PI ϸg 2',tv󩱃e|~$Pe\DL 8@k6X*m`5nx7ꖂR0Xe=!5Ǻ, :Rо!3m]N`-mM1PfK3ԊA6vOJc(q !Jg}vn>cpx ƾ žĒP#|vK{W)Ō/y)xh0n NS`ٝL@3X;?yo)xvo~:sH|m{ 2TH9TR!D> IY$+HtM+b=4BTdNVU gz±.u0S kDjm]n)E%Xma>3,`q>]u".b#Kjx/u?]R!>5t9 ޯ]L}[rK;.)Wȱ?CS0*[Bp뷒7ͽ-{/Η$OcݐR-<8N#ԛM;LX (B90"HA UyP9BJ擣 LJ NbK Jjr,A-⎏ aVf6`|ܵ1&fl[>'_c LA&a $@o!NhĀJ_d" Dc!n vU>nҔ|uu,Cڸf*xvQg=i >Ct)-G@9.8M||;} aOS ߬<&<2t=`0*pw$Lpq+#:zc'UAA 6E 2%ILȔQTAȓI]a4LTONw$&%"6SV#eM 4.=|91k).=!GI=x#*gi {er=$)U)K]&[wA]28l^G/WA6|}@=S,Nӂ03#WJºh` ﴴhԇ@i-L}A(W8[tu@2ܝ>Q zEGLbۮƥv~-~]'im^*Ag܏ ^U$LzGdG/>ڥ/F]$LSvk‹إs*,hH392KU6L\DH̏LD;[5(@N(' >Y[tOSM j }v_[c@[A8FF]+8tׯ\\h" (>&!OW"/RA 5U1KMI[|Laxrح3LWA]*8K&In&*X&7Z L|&l&0[]!5i! L9_-LXF4SH Swg$/GXG"C1MUBmdgLCԩ .=|9B+IO˝Tиxeox` &c\&O`$ݽCvy 5Oc~wZ1F& &͗|ɮB`C,d>nY+Dzo1a '&MJjv3G[)͋j[xq.K\RXWeg_rZ1C[`~W;bekm3E;G,^FF<3RVWZ7tаnLXa USA>*y |5 :Vnzg@jTA (%M뷒 5[ ByC@H9c/REV0N۔; gaIeVy59a1)A;>l6W̯HI?R{C7UI(:-Y.`^*+Ĩq4vwk3KM. mxTV˜8mvI+.[hyȯ߭TA# >C;C~w-8ߋGNA#0?By0E.4 ]D"9%:Ʈ: T@4zE@ⓧ:T N$z}($WA]zrDb 6).N3);K(h5VA4-2% 6QA13zFi=_)W-dqb.Ei1u+}MUpX/ QkCLyx壟Gpk؃*Ak hjkLԤs*+BOݾ"x6UЀ]޾}xb+k(K`:_@xB]pz= ['4' 6WAy5ܚVٿ%{?2k$T#tNnSLѣ Հ;fHH!%D=6ERq"EiSoq-rb%qȺº4U3UorX"S&WÕGtyv*PVJ(Y9v2FLsT0]R2zU_g{;g\'rxHb"F^plk^4 . φ LPlj*s]b{۳X1 g_'#듿Nm}fVN&.?^L&kQQ\W] WA3,8\WUp#XG@rHpv맵qwoPIdD{{8R]XQ\O 2$ Q!mBbkJJ*>{jSAX/f*nVPaif^S$(6cqh`l I 㒒1ڧF4rvp!慹}ڰaRCe?kVЙS&E&{Yt]9 |2qgeqHp)H "sA˶MSV.`sUЈiFA2f3SAs*x!Ñ>-IEP~BQXtaZwҏI*yH OnX :āRQ~cj^~%V!Lj-'X ^‚ł),eEQۓU2lA^c2*^RPV"Z2,RnzŃN \Ss2PDev.xch3QxĥWsMf=bi6AHh'M4{WAu>.1ҤN*O`O Eu jqoلDl E"q6kWsH;kڅF|!|9lpǏ[.` t rS녶۳W "a#~t(<\qʑы O8 u?\}H~ 4HE o8y kKĀN d){ryT>#PTd-*h\YQ0Lf %!b$mBQNxJg4WAqV5VM"[SR2I@ Õ֨TuH>a\]]fݫ+:K{.xH=']5;;gI2Iǰ-I,Ꝫ͵F<:_X f]ZIۅ*7 .u2dpʂj݊?X+ 5_ nm.W76&F*Q{[E{4D @ҵ0>U4ToX*Id^xr|oJSB vJ@ƅΆ-wl&&!*, %6oxDԬQo&[X/_+hLLTT݂ vDV@EҦ!tqK*w3^͜ Ux]2idr *Le2wE$j]Jy;kQنմBz5Qg@ARDf L^Ӎ!d4+vxEv3ڮ 򻴑c: VP9V7\Xc VgfA YnD ʸN"rbaXsƘ*hb8pDnfPA-'l?ˍTspv{-0~Ŵ>H ms0EP'XeMYvjrXBRd_h+}?MJԔ<0"a=P* c[]k܊Nn _HNsVWƘ*hbhp<3&h@v vu U.q7DkDBK+x a INM+"qBr׵I0 Էdկg14C˯Ʃav_hSxu U55zO%ƶKKAEtYlF/^t#2\oWY}*RcyaBsI|c!By+ eԋÿQSP RBjS?&&Ƒ!mMȃT ȿZph.Lk _3~B @h{G7~"YLH07:-)0e*Fe%n`7vXeQĠ"ax-mj*fbG+@+MUX`_YS`uPVsNJ> UQ eY],Y! !\+he K|q/Y8a"WCۃ3WU[ 7AnfZjS?&&&&& ^?;HH_Q! @ +`z!Gқ$ƧWg'5?Bmr"hy%/K/RRTbûAlwSQ'׳ IԘ;hpeh[UzhEB$9b>{FJJ< 3rjE.kaH ZU`[]A8{#4E^;1u0(U /:[}:R9X AbTYt?_-Aj]TB"}¡M4TA^7qP=@S¼˸s8 yNCNS%A~'nڗ@˖,EkpMt ?vcږƯX2,(FO63-yIgU<ݽ,unɵޛUИ+}X-9_W34ަğ;SAW O.[%{SS`?Ґ"|D={e' =!-5};m0_(ʈgKp^ {VnBR+R*Zl'Ege)hIo zrIx(YwrrR h)&*(2ղ~G;/')L^>KDHNp=)HA UqU_ 5/IY7#;~xTjDNBA .ˋ#:)$6qU= n  RpQ^ݏ^x)8F )Дj|D ))ΊHMYJ0Wm5D4ND]hKޭrrRJ0Tk[Ρ ⧠)`M|<CHA A6 ' ` w6Fa JwvZ`w6RC x\ MGw/!iwb]߹휀]YN epd"Y-EF%[+MCdz3$ t8U4R!1X@/> OJqTB k#u v)] Tɕ\G| v,{*ArT"@4$ ' "k /l-k:!{HL(CIbNh&*n&ACN-rU,=hfya2 О=T[Ul!KOu*<kSѰwIBo .T+ Tã[TPIg*h bͲg9ZhDW2o ԉ8@`]Lq⢂T&#XYN<8ONK]ܭ3t -5#kCw<(7&&,ʺ*-*3T` \$%AdH9Eo|PYT.:5u⦂2WTArLc즩5T,m zpYPeߒ1\Q bQ IA 5h%Z~TI%SY窨f%!aV*3~]x~8Wl,*7^/(\Jr0uj ӸoSjE8E.<0.*{dqi"V 6 YfRu4aż8.qwVC y]4>=\%Dk^"x/ ͎;+ãBM86Ƙm8"4Ђ&/쬼 yU ZM/|1?^C UP7`Б@+=!^5R-_XьXeU.$'ٖ\b$9501tȺ q;1-᪣'RKN"xU!Y*-*QCv*XB0L~#h-6 Cļ8mvb-V$uL)#В_WLa"$ĩɺoA64k )+eRE~ ?wW[q$GAI&_W{.Zn0ۨBmh婥v(c"gkxP#=nV{?ݵ*HiRAŌ/ 8DNw}Sυ%g10h_Ya$Eh`~# .F(qʙZT(UjHjCT Qh=jQAaP棃;;!xHUۍwB^Mqfq*6ֿiaU:O~c\W\^ MrФw0^bNF*pQFD Yc8bƫ9kH^@<9#kXJR+ƒG"NN\T05 aUřW @ +3Ǚ?+xS`ִn| 793(4a~?y5!lqيļ:>8%у4GE+r$k+$4^xV06&qNqQA__) oPx*IzM$Ak_F n@ȲBPy-h8\A+P SlBa~<>}C~)u:*8F4-^6)J4#NiESUQB$*@!KH?n]PRRq6oUO9I_30ؼwupWXⲢ,_'< Z,6Di3͋jq-Z y5#N*>>µ%$0ŧTp"M2a &h`i`@ h ώ|S[a0TYЧ1PبtTRTK<#=< J&@@2S̘'NU0e*P%A B1!b@ s< *h%̧gՋOȎCYAù*flUj=C W\VYȭKA>줂#(W 8ʞk҈"q:ٍM UPrꨂpPe08Of=b(kUaVS<*8$ ?h{N{'WUA<>&0w`$qp#=1}D4鬠A#L"s;+谋*Ne5Yuz*RZTp K`C}xJ "FhI\mqK'kH頂# .6r"lWԙ0Dx,4^ tVt3ĽQGmI={פv*x40<*⏍<V^[Tǿů L_'#Z2J Dj\dhE@) QDѥQ 6D<5&\B[ƤK}hҴ}/_ФٝˍTf\nv38PBDO_}|hUP `(A1ec<nwK b+he*}i6fdvJXuU,TBBJٸ԰tfTP}XdT+" ]R nsKЀ &1e/N!Ҵ ZŔx(9izH U̡1%a9RA6zr(@UGۇQA&.Fߗnd@}\..S/jN+'QaeJ~M@xt*H +b}Sh`A}>0_x~45V zxɅB\iՒ6vHG>@.X:J_|fmLx7~TP/ NP P|o$7I*x Hlc(YtF& ^9ۀ Σ *imTT kM1q1*rϼpӭCep*|#Vͩ8Z U_#ݢ, PG9vgI_ c{a<\7Al 1 !@3Q,oǡ2Bx36T<6}SJ3mB(zȗBl~?/}f sbYϝ/񅚠DVP[ Yd{$ c9鶂g0^nYvJPu]%A(va9Rcxi_Wg4TPAC |}T~4 :6  }=w~8oi+ D}nj{RAt]{5`WguWoWq v #N?߃ 8 l:UQAVq+5fnRA/NXn!4'*>0Vê?bۑo(:]),2AW9N0YA+ж-l"OʍuZׇ6:(y){0G*뻽꾉aoa؛bnM>Ux.&V > \,7L8qUX>윒k`-r f)Eďad7:Ѽ]vr`J%Nwipj,P}8٥bV@(Hqt䦺˜&kV}N: 63Q!/pS. 65A}* ~3ϫ3cP'-/C4NCB}EDm[EHM Aw&BXv&'̹!y{3Mg! 3,>=o9o.!V_s 5A3)3y˽qÈ]s#[1zKK<T=⚳G}R bWG[#aʹztRM☦>>ɗMYpT?J@#RAWv?agk,WA9ylxG- VjXFn4*l+%5kۚ'rI6nJ}BD.M=Z~[./ >Lp_m<}TPB+2ϨUnd*L\2, XR)yEm;<EWD룂&TVXxom[wyI>QQyd^'r} Vn1/ԅ Cϱ#`7\_(S7)U`tSm6A@iEXyX]^N{01&aDkYJ_xuuWsTyt7ݩ-j+覞@qϔb|B+jL##s: VRB*vk)nfgSa_hSl0łMd]̽Vxlٟ݁oY}]Ա o%[x>{l_[b`wAG )̔|*B[$itDpzuS&4RsԪ@lFnL+F.(rݣu8C4 })8gdJ * ^TЅ&NA"N,3,ӫY5NG/]]Q$Yu0bWmSS ǩ@±'|2 ?0|*4ʼn\yD-mY2 O/6E s錑z(P0f{_OOX_xK^>(EIL})LPǚG`A9k[iCaZmYa6.VZLpcA_ZA*1K MRA Bl>TopưElO5[]qcA d#y\_BA S>Ú ?!& {Gf9x&Pϣ l i}4՛'{8姝Xc'/X{ w(@O, V3zSAz;n\җĠ ZLP!bSA*p5걑~S*P(R+D{Ao(v,!(\mMDXp͋L7vهvO R0FURFt,oe IJ4s7jw4.ۯB` [Os,W}AO3(gW'urO"$.ۥѧt*XB(٤AFD'yV>f5SH O,K;@4I?_)T*P({R2<ڣ %,(Nd *(L.%}݌4HǨ=NO3XM]Is"]5;R}3zZoAf#]f D{+.{/`褀A*-QF>GTpTPBP(E(ׇNm@3z^?lVtV[pC(%ҖN^S‘2NP#zBlX0J PZHW]RxYO={ CVE@>mfOX%ҽG)uۃؼ#n#x RA{7BSGͶP4wR%k7ؠCX9-#_HS*HxtG *T( }W<:Yo5Т6)?)K6ްKP *8`LHS}ar\ &Ra=/$f"vvŲW"5W]iԃCUXn/zܡ,*:xuo3e`^ARQ&!{AATPHf72T]ޟUAbbJ * T} .sݭvKzniTKv٥e%5;:|s%Yؕ&y|y[4l8ύb$P*k:ICPfW˘3m褄v|zuxiGy*R7YBeW^$:d K Sw>. R6"]INI ; j"u8 eizV'|t_ *T( MAO۴Y]$u5 Jz: Q:Y.{/gUp`JW}^̲go+ˇ"V LV邹y5y3:}(iZ蔎iM\K d8~e>#{|7~a'?fg=`W.3PGpDӚ<4e_+C_ D$ێs4?;Ǝ *T(w7ia ? 1=m*1h]Q[/D4VI C0-$_!P"-[CW~|/_X,=<Ϭ3CQP>7b77|98qw]YCН͛"whpK8A|Nd"mPa#|.bEL}5ɍ@HQ~{%h6QL6|;Ry\tS ]acB"^:lDT-@#bkz4v*ݗD( #d:M.VBITdcfF,C}*P8(A-.q\ѠA!"i|"hߏ.֥W?[6&٘rFLxC_ro,MtFdc@Dݯ OqM $ِgKANLFzWٸ7J_ }/KwQ {S٨Oz(؅u~|ثz앂.7CY~yy+A7t\.nh1EAB!vFAnfLUmWM>и峰i?ZnGN( By(xŏSs Jj}Y8(Hˮ0A $耘Znoۓi/p2tQ)xQ);8HA+tv ^C'/>8HA+s"1y}'ä ]Z*ξ ) `SH+3y}C$ap(L*1ȾcR eM FNT&ہb5\ c?sNq I}?86 kSpj^:y'(XSuA5#'5t !")K R  @,)HAXR bIA@ Ē[(RA@TPA-T`KRA@TPA-T`KRA@TPA-T`KRA@TPA-T`KRA@TPA-T`KRA@TPA-T`K:o=E * l [* * l [* * l [*;FGq10Ӵۉ$آ6!J ]I"tEɪh7.t)d,\!g]$!" D$"2ֿIAgP$"2ʟ`;uYX (G)ug,]OSKMe^,sǏJPQcu6ؿHDLA""%Eu{>2-XBC"=2TkI:W^v|TZ)HDdRPylWRPkw0DDx JE7-K1A9{umrUQA n0̹RPbn#ڗ%J=ͧ/CBc"')HDd$SPAӵi[hWOB]َЩ@?!+ Q؍HA`OBc')HDdDS0Xvҵn18HYx}_Rp;,O1K>JO|\bSD@F>Rp^64&z"DDFI4pr\="^qm$s\X,b rvwգFS5\kl-rgR 99Cb %,"3m` ,j 3ɽ"UoG]"@Rp c')HDiI% 8~/\ 2rAURE =^V^LPiB }>y1YsޭZ(3M3\ mcgkzMk.#X*^ ?21Z) X1L$"2LS;|*}+hRPRR"8Oх`-c^JnHPLgdߘLA2S(3M&2"讌$tVuac3;ZyM }6*sU/sؒFϑ$ݦc&2`LA""2S@Nd v;8' HA%'N=5 }F:΋c c&2`LA""0.H}(Ur)]})Q JAF;0dLA""*=X^Rg9ur۷*i8`]uR9(Qo)>_BvelLD )HDdY`X,By!s  D΀w=iRM$p$}vG)hy}: })誉5` ߘLA2S(HAiud)Ԁx_8Tw{p<%яLrYsf5~y\x^pOA͵ Q|c&2`LA""LӻOpT4+`V̑Y2=D"12^'2S(LA"b )HDLA"n WoFH),T KRA@TPA,T KRA@TPA,T k. ph0 ؚ î #+HA Ƥ                      uYEaxgbht NS 8!88/{eP\ kHK R -)HA ҒHK R -)HA ҒHK R -)HA ҒHK R -)HA ҒHK R -)HAê:=lǨz})@ u =9yZcnr7Û^z~>XiN8)ntͫ)j:FpYy8[.{ 65O1fRe|5O 7`< 43M5Ú-S5xTߕۥt͛/^ػF8 _I[$j1D&;Da\X\(̅ ^ hN'ٞ=dۮK*]} )xzzڟ!k[)~bol%)(H˟LbS0 mk)C BH !b (6,xyg5 :Q*Šm &)Mm5XCy OTry̙9J+Cp, ޟWvF{fws[gchPtj~ O/?]ɽS-6'p}٬yOftF˕xR%:J;\QbB,$Bt3oRWb}p)v tx (4օbcE5e5AY Y7$#,O*> `Fy~VjlOP}[rR0L'$Bt-%8,ٳAhR0a)u>)8 4mM7gF3m$[=+-xڥ`xX& >IlM H=!8o1]O s5OlG!B`衱`^ a)mV&@ F`UlZ>beXsvb7gaL*ך6AߠI&I~AmbƢa_O&љkҖxJ,&x&6zG?^쐂ybBRP!D7R0=m)yПk`YE.VAmS0SZLw~K#io ddy6w4]) ;de:q/L*i0i4<Ӆ}k"uSp!$Bt!$w)5ao?lefA)ԥk3?%l0^G!"Dg˵?pHlBH !O`i^*6D2aU҆IBRP!~gY C!!+MmAokj . -`WQAqI_tpSiI n8ϳ3}ǡ)xGnZQezLQ+wNk]-w V n>_8p`DӳQՌY/ǿHA[x%*nV1ډY)j)Ы"l)xrd)@ Ptr 9;(5cjo^ٝa R ):M $E R YRɒH @ %),)HAdIA@ $K R YRɒHSpHʴSjpuRʤy1J7Hy Io1ƣb`5F[Pou- IA?g1jif;:^A nzd sNԎ ͽ-/a/]\X^HA~s,jq]DB "4&Sl.npA|t(7w*5tTzt4L+b-~@9ͣ)^R1U%`Jv/#UF Sj6{vC'dSjyb**sIaYr'i2H潓xĻ@HA)SoV"cıP34إ/m uUpIJ`9&<$/>w! ,RS]-3,{6en:-]I'[i摶גʼq2)8|~-?^Eze\^ )8Y]S t_OAif!)R:a t)B  HA t)"Y R:@ @gHA,Rn0Q^%\.溵;0${0XAXgWp x+ V  @,+XAXV `bYA IJe+ V  @[VlsϪK&q#Ɨ9ADDOw*QyݗY)DbgS*m߽_ ` So`_"HrǗSPe4DD/JnU:پSS\PT+Sb ` W| :nY &VN3ӵ;nd^4kL;Nn/z -ƽ.P;k$)h:΃k j?+K,MKTZۙV1QS>^HooK3i6 G .T?-WV[)u'R6iX~tOCL@kr""^#hI$s`hSm@[ZQ~qJ ֕0*TVi $;X3 $"9_|Tqn܁gkD0Nn>PZҗ}ն)(]q%bQ`CxK2}E 7` PۧX`\U&WUaXA6 NՕꧠΛ> LA""|˅=qq.*ehЕ!(I%\MSR0 |"cӖiBѕ%Euk`N֗U +U@@UL O6fc \ -i^LAƢ]\˗C xy-Ol-NZ ` aT&nj5=yk 3jyTSpM]ܟR )HDD#)<J+g2wl _')x([z"yo4LAB .F#OF)1)x϶|^E\RB1So[fb ѼW^5( S/)lHW`"JP2 a q )d1)A3F a4&ϯ08sD,<qwv s eSRp"W륕SL#Ŋ1WsSa <,/v/)HDDۓڰ 5$ s aNA=4VHCS'G`S@K%B)80nāj)c J- CQDD])2`_8)X]$`O"R0)hqͿ . y*S0e'RVSl_0*nD> mK $%_R-Z_OAeov=gx5*E$H1x);rny L i[e) ΟY ^gaRJJDBSl*5S"0hKRpz*b ^ûػvq'6R!"nmHAIJnÏOƕ4|  ߞJBS7A3eDS$i;V>b^v{<Y1NA,NA cy cS1蜂y cy_)Ș7q 2ƘS?s 2I1)ce3>;a7,7iiNNcl6Ia)!4 ?r`S1)W$HtGm'ءG?a\a!0҆6sg&+m5X"nl1)})Z|):L˴cL.)N,t )iU꺆)ݿ4OVC#?(stETX& HHԵ`I0MwHLЙsjLc €1E0 _Db县h`<*LuĘbBZn^+Kk9{銐Ra<:)88cSRoe~]y?~3Xu`n8Q~ڙ ogDS_dVpqػU;oU%'L/ݽRv7)N`)9kLAZSnP2JmV%]V!j@zd4s9~ ŮzqݠGug kkݽpSTJv(EY`03 )Yyf%b-abn`\\%kV0.n4q !){~81)WgKA'{uK>܃e}q|Gbw+wּD,i6ϽiC;)|W46Vh$K1B#G[5E@Dș{qq @?.@9w+fvI+@Jl۳]A{rv,b"d1)*mk) h=zh .QbRQh~x &)T ZEv T!dh3$?LwrCom2eaa1Ʉ0cmYq;1`eE|0H49SpRP[)jLXo!:mqd1)/l)C{0T:Baև``j١z IMyiHDs;4)j(y8SP}=}FjHläw۩ԍZT!eF.SLAي))4k&"oDљלp<_=>& cyJ_ VV˦j@.j(wQߴz M% OeF'Qb撂^ fT<""4@;)BS[)Xh/SHf8S3$]5 usc2y}ӆu|M2NAe#/3 ],H=JhXdU%A'`54ktF$F1"B #ML]O)'DRJ)x ))c(/Դ<})pImtߡ FтOS:]F~NS՗mDSD`+ <CR0k,a V)7NNADz˦`2e%t^m긤%HiZ+OBKЬ[ ~Jy%j_]Sna@X Gᦵp7k'`[mun)eapXɭEX } =у^5hLR)6 8cSL'TGiԁe;S=złJA{z5[^f)CJQ|{+ўqroONA\ q}KFpr"~{VЯ"z0AR]A"qKAԽ?12kDI){ӢDpWE"&>\oe;}VxOSbq{ɔQHA QZWRՃ=5.W*\Cy[1޹`x{<=JEi2O J8T{ݮ敺KAnWp{“W^%[:ɣ e;)+LnNMAi[^~B{W^OJeCOR2 (G)}F:}pIfrvD\Wwo_D݈-t{n.\p<ؑ$W] 4 YwLt睰52 ( S@ϔ,R2嵑OJaHTMp,C-,Ҧ )F12b_Rs,oS{KHA0Ӂ++qHA0sr ` Rp` )~n )8ϋS `"R2s9AR0)F9ùt΅OHA0ʯþG "( RE  X RE  X RE  X\L|!*!(2gAp-(3 }F?X% hˢisOo JHA0)x|)螵dy? 15L3tgbs1\X$\b3qqIB+Q|y VĻoxP-R pR%PSn} gHA(IA9R @Rpw7{2~ݘڱ?'_J^ݜL~KQGoԟcg+5rSbtD `HA(IHX'Z_1vMH3Lʶ t;g+5rS}MXR e?)bN6jM aG5)ԕ?礠?54*-h说iSfslGr|x= gHA(O\&GԦ.Ud+o ޷)x$krF)ջ: gHA(m͹K .Ũi+Iio )d&}9[ g_BO %S 6nzoMI°!{R&+/QJ2ZxW )_얂t v%eH|V Ν(ۅw)@ސP({JO` kC2L/R)8ӓg"2qRe 3 RPQ jE̹b~J--'QFoW )tdLdzjЎ]qaS̷ܑ|4 BRW7I};Q+س)LujO[#R #kacIA5@bTVȌ6;eIh6`NAh|ґΝ({ ^z_R 0R?ԜlǁeY;ƣnS*ʡvMFsgeJ39C @F MA:"NrŸ,g+윯FP(E 7o "gHA(`'HYT^< OHA( e)HA@Rq+!MAC HA @ [D0 . MߨA`N Yq~  `8 cmMb1]!+B?҃tHHO8O҉^{)%1|,亜Ir@(`v~ELyu#LH$lRJ$\yg)8 `L-p -NA(+~e<%yurg U3 bqEagj; `^9T{*^߉$_>|Aۏ_˧`71ϧrZyAHF`@!L)h>`1UlྺgCKA}a@A< ?Yl 3k`S16ʥY Qm\D~^p#Җ]+cq!?=N&ȒxM3KdHhHFd =OiWq{me 0ښ $ (-[S1v9qEOJB|SZp2; K4QY rF!}y@\1}rbS0N4.-,ӄ GPBkVƘ c &j9~RRewITɌQd ։.>ŊlIOw)bɈhD]K)B D<|<8cllv VS\d^cفߥF+S ~.X5 L쇄TapUJu 6ũ&|'\() O:jsM)c;eSp*r/SqCUי B\+SPB<:)hPs6IhuȎQt ¡CJZS~tJf @@k@Ie21?ZԂ6)>S=!>ئd)x&D`z y.x9_uěJ./g4#҅ɁhL|CAzk`d2P rlM=ZɤIԀVpk&}֘,<$'CRYT&VD j M9cDəd)JFhS. jP9I(1k ×MoPp2yLPJC)Gh*8дDmcQ ,GRR~#fCOAdM"鸈HAmHGໝ@YSM)c;eSb.~r=:?aZhVC!B ja݅nXx_6 c$ץReע lq 2NG q8wv``L$)'87WHA)x~R E nsށ葂ȒȒȒȒȒȒȒȒȒ\?kqtR t*gpwr5p7 3HBAMߝ%%wg@c/ ?EDrK)("JAR RPD$"-(EDrK)E;HJ V*%TVh^;HH V__8<{ $<\w~?_E""SuS"'@)("+Hg "JA@ !JAH` VuX"Tfb\.X3TF*plF|MjSN_%SdYVM)(ɕKKqsr"ŀ݄'M<ֈ^;)X%P J(EDrRp8DN=v\kK{FG 3*im&q(|o;_xl?ZN:+D捆wͦKU*r}U)(ɕKA}M+3qJ+-ϟQǏ^赝B7.E*Q ѥ`Ԁu>? {Ls iEQwqwĢWu{PB]j=8GLK)EDrR8M(7 S wSHYHMw? ٭c"ab,DEX X-=:HQA@TPA,T KRA@TPA,T KRA@TPAU+         Y* @ *}9/<ٱjSq3С3'8 2t QC1ա !S񍼵A 38ӧdhXzqm^ k na<"A P@ c yXr.A gn)8}lR O:FS ̥)@S'ǹ=T )8'Rpgzxrk)HegURR"1NcYRRi @ PT am1HAKAV|@ PT n2qD.)@Q)Ŀ| @ )椻YJ^  קl'If7rrqeHA?Kɬ/UERp}J]7U9)P>}޽ @ |^U+2?}|,)P"SHA@ M R~[Ǩ QEg ZV6.Ҹ1)jBrRۊiN.%) @ZRiIA@ %) @ZRiIA@ %) @ZRiIA@ %) @ZRiIA@ %) @Z>j-ԦR5&>ʰt.+`)q(6f)R)x>OCݹ̮mi)Sp{]+n;.wY `)kqަq ٷ0:Z^\̢K0rv@•XABtGyh< ?8t9zc)RlޞۈΡC\ mJ747g)HAH1G͎!n7d @ PB i㡾oR0)@ )8a?)P @YReIA@ /O_'J闂Kf.M /?[IAR 04)PJ-IAR ʒ(s  M 5y{ `dR~ٻc ;& CS rC쀀.(v`$KvZFZ@)]S}M2=<9MiIAR'=. @d$4tѺ Iզ'u[;h|>%5yú(R[V^a~^[jT5LB"ZTdR W2_DoNº ]v "$|ďDX^YSRaɛ)b]JWA)\}9vіSpy<>WSصE=JE Irsݵ8ڑ^\TLK *J}(9bzcfDcvXlC ʋ`CگJ B3P)(=%nԢ| ؤ7ק/򔣦Y& ÐT oW`.D9gQuSRPYe0;,h"-O{*y&dR W6U !膞}3'֧ aYa-O9*TtZ٠Y@!rRP:,:t_\K{'+Ճ)XOMl:%RS+R`[s )+/_`q .HQ}8 i*~Q3Jڢ'~y۴o)H[>5K> B)9RF|%iX&%~Ʒgo J|'Mŧ3-;T f٠dR W2Cѹ쟷$u:ǭVNG nn:緫o8$ )fǿNbl`ٷ0<4uI!]N-M-_Ĉu2 )+LAZ!ͦ$wtTHC4YMgdq=jKT'ls9/)&->FYHA\H Sڻl'[-v.&mXy:*>㔦nseHA\f _k@#B  RpôGR W0O)+H 3\@ + r )٭c"B]D܃ @TPA,T KRA@TPA j#SAT KRA@TPA,T K:&[&FvHT dYA dYA dYA dYA dYٳ䭰)aZ?<ʲG9o'a{^x)АS Bkō m!ԥTXbT x({lfRN ~+1/) 0: Xt$G- ςB݁rNvdN t °*9(T !l} ֝NォNrB s~l$Fqq:RtS}䲐ԃ&.٘Ko҄6!pM,%VAE)XuUcC}xCS0kxҁC?YH%bOAk-qi@!KzKSYW$akፙxǮlMצ`A]k#, ІB;hvquEFPhg]] A;nm>nQ V !lJ4NN)ՉVùj:$wRPsM"S]Zv+doDKZR M{B~J2bͤa^)bsqJқm~mB:6:Dݺ*nİ6a"E6M)ܫC3yJljL gy |!?YOfR0 c-Ǣz<(Px8ی"S+|G ;|B-_j, KF SB#k߼K _ȟt1X0)hW▂E՟SR?{ /#{k}xٌN}c^<SAH U] ݈#} @H.t:LAղ6+&|d'0-UϪ;5|!;_Oq*!X0)hW▂8^{W.b>)(.ɼ-KL$/ ۵KY͛jT L #*\f}݈ lAJASs눳\/ޯksʼVVm )BQx0)hwv@`gP9@€`% ~VQu_ cPA(*HsGa*E:T DҶ @ * *K RA@b TPAX* TDHAi==ކeB UN3 2~LHAi޼ݥ|I^u|-pTboް,YV{*at5r{.;FV3wBg.S=N(Rr))҈#FC{[<[8:j!FJtn$ζj4r~THAJRדX+jp4R9U -Hb9M%oMwN%i{X]Wwe)xuwu+Sa'WJ.khLD^FtB t-au7i-b L;LKv~( )V)\ Kd|("}B"` m$:c/= $Y1˝Z-2+ٙT? P* Xx)W71C)i"Ss-M`tG'v%j=\JmNkmM6~THAJSPjɎ]1>J$W:f*W]_=O@bt|l* b)V)b &w3m1<H柨3V^ u&)8m#(RRZOѶ>c`X{)uznM6rdP6 X)DZR ?e16NRv>i )V9xWKߵ^ԍ^J^ u߆?ϝ:GeB UN!} LRi4M A8ntuz?i7pG1hgQJa՟ov70bŊ  8g vܯ2׹f HAHuU=`7{w25q[xƻx]x+li2"2qd! Ԑ>M9l3)x(FĚ_ԑ]fwӿ uslJіr) ",6!7RjR~\gC.s @ PA v/%R #SJ 8} G nt)S21{L_wRSuK8'\)4͇ L1جTR 5Ӳ̜}k2_8|jHAjIi@ Pa iHAjL?_Ԙ@ R)HA _a0pf!f V&^RЌyT0,)HAaIA@  K R`XRÒ֯ P%@ R)HA2-)@% )@#HA1HA`΂P#藂\(K9)@\r a a  a nv#P"O zCa @a wǦ Q_: `xd Z WB"&'aaa GS___[[[JKK~~~333ۃhhhjjjWWW9::ձIII#?FCDEغƪ999򾾾gggΙlllekqҴmu{X]a_ekOTW)EPhpv$+/MRU)7@pJNQR7\bf4[sSX\[=/fAsH3I4+0N`F3*P=dIDATxAm1t?q 叠2wR#YA1 "A4XD3&hp`M , DE48h|/3pm|;ھ^{͑iΌ]4x&I7<zel9W#N~PNŪ64Ѯfv*P] AyLNĦhʙЬbQ|gqnd^>2Fs<Ԅ75N}< xlīCs*.F՛~;VtD1nb ͱvZ Mi1zkeī;ӃC3}TBls$Zy\M'Ҍ -Ho5iWvV ͼjNZ84G%4&{8%UHIfYÒLKf$3C}=v{t&Z44G%4f6U+i>SRRbN"~*@ x5< Kمf].EUJ[I&X3{_@ۓꏳt]Wg + tTh^=נ59=l֠}2&C gLd[x,j_*jjP2x*)}yf)H,'ivU^o6-a z@_'UUԺDշxFoef6^ڨGNUz& MUݓmH`+=$ه Z$RN%4VT'@,?_}>z+WzE톤kk–EMywv+:P6jCc2kPNaَ+0> 0SFw@AhP&{C3_pA Mʳ9&dIhJ GfF`YVIfi1&2G44;`2GIh,F M`B"4؃M 4v3{w6`tn&H $Yt,d'*`,FMK,sS|ܙ;_P>弌:cph.U$KqC`y 4y`e^ 潁&D͜0J`h&EhfӶ1m=zYo}lЬۘP*Фp/ M &&f)4).4x`Dh3 5w&M :GuI6ݫ Ff=Ї&Gf3iBbm:@M $YIh2W lc&xGIB3f:IyfKyU/f&f䖦ФXBV{n&6f\hRM'4NZhEhR, p.߸64cV.i M34? j@9) +C nArh⚖XA`(rAq`c& ^6o.- Jiy#4XUy\nʽw29Xi̗.I5:KAOmͣ 6x}/,Q.":̦ _qUO!hjiIpftLJiLol!(Nƃu8.LsۡFgſJpLyM3Sji~~l勦{&ъ;DFVh`Dsf"^͎* _^B4kg;7M|NW V[s dfOX_/6f-_mb|<̭}ʶZ^.RSKL4I8T,yYf\UZhhi/1{Y%ίWV>$FY?XyghdH*v%sXVf<85LK[t SIsO-*Eg~֛L#pY;c?unFnYb1gQMLK*.Vќ NIEh.9[B446nDs(é^}0mla/f/̸9p~>7irFƹ\̏DkFahpTǸ`D*2/@s+4r{Ĝaf 8,f7ڪ:Cl ,+@H9pWq{%LK[t Sې:FL\sWʎl1{M4#Df&jD43$|dXESnD!I,oW89q;NAJfhf+fT>/C( <ɠ'SM±s_)uea>c=(Rygw9@^4E`X.,1g(Xc;SAQj*agh; b?jh{ODM{iinaʑaO=r*Gz4?v?w6[~B]D Yh^hC.%JCpX#<9M Єhќsf3M4𻾸0 1ʞ(}0O@TUɆK_%uyv]ZSpӔh#/ I\noa~:q n$Y3IkK1=´E0 bQb܇ϛ{&6*z4?v?w6[~߰Bzn9i/ Q- AVI48r~>+NќTfzj O4J rS۩cEinfW9| T gIjF5Jw.2[1xٹ'y9EsY`X.a9yx ͗h34FlͯjU4^'›´E0ۥJV|]|O,ǣ,p,ݛܢ ]<' J_,s;:ڛD*-:sf0΂ \) {;f AJťr~w]TUwɵ0Clz'Ve`td_hFP fFO4#/h& {a-L{U_2 qAjl9BG=XXwL*GֶfJfRe>3“ f7Kcsg7⟍oE3xC( kydv2`nLN&"RŔO|u&_zHS$EkdٮCp沒)Edi6"jYm%>֣czyYg0v^X.3$)Cٍ`+piVg]´1^ C q݇{&WV z4?v?wi߽Em0m%L1"@ᰨx[2gF+WKcsfE\w%q h)]P՘n{m΢*DžA ev4LL(hMȜ}{p B4VTI4@@pЭ ''\ siB;#Amu+<,>&~tO!ʾHŒ|Fиvqz0?;ޤ8b Kt֎n YK:(n N{-@}B˖^nwO]2,ry' )O7?/ ^Xyp8osM j=dF}d:GYzMI[Q{ΙӹvqFuhw= sC^͏PW7qvǛJB>p?:zE`t;rv6M{uvsRE+U*4!mʇ'雁zt?UYUO+ fg`W/R&ҽ=%̳5U6+?vZ=tR#ɵ"|Gd_mnS,C+I-`XҨJӴkmT='AVibZ9( wӸsp3߯b{Dȍ\z.^U{Ni2܃Crz<+% LH)h06\*@~˜'k.S:,:?-;cGc|>yvv@ , LLm;nlrk>PZпLMJӢ)/:<,)9eBfoȖyim(+ӢL`;j߂McDps&{ӡf9.Bn4s*f=6if2dhDbB~FAzDA )gx) f tӤ &ni좞ڜDRe!6;pť| 'KG8>ӢL2cѹ̔C3\V+U_ }yL!Дd i;BsԾ{_H)n|4"uX$0CAٞ\C!cø,(`Ig*[pQ!6p6"4U@V|y# MAmZDii¦JLqm MH~>R`& 29a MC3LRiTeU@f,QeNm (e2 yy;wr.4o2 ;]_1'4B3(d6k _ MAxIfPجMf^h!4kL2 ;Y3dzQP$3(l&334ԙ?͚!ShL2fm2ͦOmq|ah^aƹ9~4&.fžnCvGnͪ' ͠ܞBAhNǙͪ'݅t3\ž\h>͉DfiC(8|8 `yv>ٻca(CЁRwv\`l7+33`8BM'e智 5$4[7IhxIhCiieJrV'WfieLCe3l Mx _BgMAh"4x ;9g`cW'<4[zBs$:j2&7aߎM O e Z;|lBs48sڄGޙmh^pDhBBt &&!4 4 @ @M:MBhAhBB?{wTqZcz5@:XXLP"AJbu<ɤǵ]>_}xBSDDDDBSDDDD M1 M?(4EDDD"䴇 ޛDOoJG_ʛUnmr KgƗ4ns{uG_^yY`n/F&mv8~ecߦJOc%Bsmf+nv1ּʊq?OVֈeD  <=4 RhDy 9B3'L/"q_f""""!Ef<0N馍Ѹ ;0]f6';`ǻ9n:>`I 3%qR[0 Mo ƷNE֤w84W7d$0.H [h LPאT^1\%u~ex|HY Sw}%)B->CCdϞv4ztɽ4sơy4-h'6K~ nƅ RhDIWf wy3wW$L\h:NYI6ic;f4yn {<-u1_n̝gLJfɲ8@h&fȭ f\ FSDDD$&ʫ7!svs0;LOɻ@v{{擃z`hNzfhJB4Q̆Xh6#~Az׹H2NBLЬP- ft=8;1oq#-_>c܌DDDDb]c Hu yR:7dfbh>40gtnw4o]f!K޾|h's 3͈_>GSDDD$kwF&6IJEh:>14fY`|H7 4x/4?]iB3TBs0 wbhF'[o fDSm#|,//40k!64yZ̵":4k \>{r3'i'rvC {^ nFXQu."""2\p '>J Xlp'>4l&ajLZ)˝xyhI:-4QT,Cs\ ft2r]Dnc܌$OAxATd6]SY'LYFWvn} -rqBsehVF3ѥdf`3""""IuYB 4V"U Nƚi[, EQ/tA!\BH Z!8<^#.΅3I9>"/e4~͆1!b:kf6jf{Yo24`6x,?No w7v95EN-e'^le5 Ё=߄&@>#oBףE9 @Ah&u$ @&IhP @Ah&u$ @&IhP @ڱ 0" )$&#4hAh0B MΡ &OhP 4 @`& B4MFh 4 @>ΝGm # Aq yX)((Hi Gr}e8^XDӏVȣ(ibr`\g) @-wV3q;X0XhG BhB~hpFqjd^jYuf6l}dcGԌ>s2D6#מw4rH۩3MB.>Jr)-&$)rk?5͛&ɶus d Hdw%;wD#qhA!MB[ )X*"(g (F#4ȬhEU:EUUr/*h6Fk)ΓkFFWRDbnr8Gyu[K\cPPL&1>{V59s7uZBEhBKER)Lpjd,"x'l_tp@4;>`Fhtgݹ3+9kE}ĒΨIJq|/=MbU1(ҭg^xeuث"43c%H:ZBE&h5/ 'FP"/fwV77x+D^ݲ @,mqg2ßcTbWf95*}SAD~)%n BhBM@ue[;E5(LYhYW4fTѯ eMpt[˽G;cN3&rg:E~& &!mTxhZL>.V°՜[shYW4E3@mCZ`t[(挹?L~R4OcX,qͻ;!P4 !cs5)2WIHkd֗s8~$q][JP{R4W4MX*ePw}XƩl|<1OG:hh:pq+y~Ʋ[4Wh!n BhBMahj,|c\_kG{ q5MSJͺ9@9 Ʈhq _##'ʐI)QkkYim]m-`H47[4TOi"P4 !cS'HFU(o)NQL3e!{쯢npY;YW4%Yf"%=!^4%A-QY׋ >/ Ԃ+Jx{d!><Mn |h3@ޜt=n}K!MB㊦AXEjMj "PkJNM@x`Mm슦B`2AV>0N@^, 5>mZHߍ.h` ݢ1*1-BEwAm$W|H?yil?ܷ{wcLkd 3QBhB!I!|bߎM(Q4K~/=s#:%4NJ2ӏQn@&QXtmH@&AXeֈ<tHht.)MOBؙ9]*+MKB`/μXz$4vn[{tGhX?X㏽;fQ0oDP4[HvlpseT\<Wlٱ Dԗ(' c[wҗ8mq!4`+wCJǽ"Chw^|!Bhɹ]3K{CS1!4`Sm M _5 eflw.|YMfܭn4DAOBsefY`Fy}f+Ue\@LMNCsc>9V*shm굝Z#ifKj20pfo7V\ٟ!4W~th|/*XhN&Rft[v'& 6 +^C\fKI4[bFhc/lَƺEjآx@MxxNxgf擲!4aVCx#1#4L9KCv\RǦvq#4+(Y~q>4Fh,6rD:Fhki*Q EB`4紣Ygmk9L:hx"9bZ%4VK=Fn(>ї<7qwhxf}saB-~ }ɷ aBJhp BJhp BJhp BJhp BJhp BJhp Bصߤ0ojjms"So3xYNmd^uQ%d |o~o3:Be[y~ &䐞4BFh`>;4c"40<:@g40Mh&8jѴhU 4XKBeۉktKuOBDF`$4iQU&Mh h1 "v`L@`7 4M5&6&¶eίK+?u6Pf/49vڒ]ٗ̆ xyrK"RW_EiY\H14+M9VԙZFFUer)d|fn]YG^Zx%wݷdiӼ/}󯈖?ʴ,zhvoN"\F}%]繹*苹&qb͠jZF|l/aN%釦@YjEBJ2BhUKY #PV_ s6\$!yl[,$ ;b^@uŰNn>"4A[ܹkFpNG}Ohg3r􁚻~<s~jË,/@CRE݅|~]zih{hJlCj&'IaIGY$%*cinJ%?יc@X,*9Wtq'VhfM8%ܕ~>$;@-ŧ]]C >w9)S 'ptaV|Kx]@{X=V2څ派r34pU4~b.ᙼy뱇 *@BXgGƜaiv0XWfhƎW79jnN_E: APpW2ǵ:Y>KpM*GCwG }ihNkOzR9d2Y'}>D?Z]y&4~j"ՙxamQUҧ8(\!4^/Ƕ`qNO`dSL7i[ ?czx)zi-FChsx1 Ppi{,.fg23y U6VLc%/.)5l:Kah' תBˍ> )eA#v^zl4|hU'DZ>4gk\Ƹy|дy|[:[QKqkR.IU ;[#BS44onuCk~@_]f\:tcPAf߂E >5@6PBs1qml<9<>4d6on X ~Ƙg6Х3G[hSr9u׌s3c&'kjcV[hXĵC/C5Mɬ&Z'V9DZhȂqMUvh1M R :!pisEukT>Ff0hٜMA֓LPq8"FL42"4c7w GG E*Pw/[Fy7T6rm;NeaѐvYѝKm/|ӻ#t2BsC *a5BڧadFz"954ӻkLph_s=h#kў3+BÇm2Aju0wPqs3w;i>sAܓЌ]ȼn?;-B_70\h7| ;ah^$td|hve,в8t4?v,@،RkhH64qx "%*";65B쨫JyZEE]мF?R%94͙F Tu< qW-Ui>|4HyߴÑw|Dh mh>$ q3P,sIfc 5^9BБ1ЄQ@S1/$4; Da$9+i\h:1Qpy<_Bl5i Q*ekhªҴb{Cj/V<{hy.4[5]C㍥&7.4msBSV/V`M~gB }IhFo̷]ho7c_E$ -4Ϳ^eБ\khγ<183 \y,R/+RWx C30@NUf[BJ 8kM~=C`e4A )N!.0Mۜ4Gg% h9)>_/&c).ɠ@׷Me aIK 96!4d$c5Q)ȉ FpĀ~uhJblrx $+FiH HՈ9B3AqZ,X6B*C@c+=`8̇k3XԆKhwewR@w~ ۦ&!z H@0lMAV34)$d\&PƬ}8&\_ /Sɏ,\%Cs=dCor,40c8ٔD;YmhF=1&8wMHY]MÔ". C,9t:_Chnt MXۦZY:IU$M5c^ *Ż&w`TL-FHy5;LhD6L<4lt MXylh3G\ls2Eq1EP3 ةϬ,p)Bj ̓{zC<^svEI<sqI/s|"sOB""NCs1 mXH`,xc76:M;\ \lT: c10yCؚgT4qcnuz M?bͪBxK۬{BSﮑ47=@F0ՙ#NdpZU:&0~W4pemmtuh7J$X}>+yMw%ktY.^_i#!C C(c/FfJ bw[hG﯌bBz64+;2srDo|˹Ӫʺ]S tKyuo=wҠ{~}(A|Dh з_wі&/O#KC3ƚv CL7 e0X~zNv(A-҄K_hv$I14a2"^[woe݁@&Y*ܯ4K|Gij7FLyᐎ6d~n6@S`aEMf 4&`a;s"'( #a9Z &ps%KQi"48ٻ&(' Yש^7YZ4 @EAHS//~sw.{e3?&b)JMXMQ}BB! O|+MBI!R4 MB!:V|c BB!E ESߚU4d0lWքA<}A͛nA XL¸g'hL ByyGK!ɋrMhD f6Nmhm+Cs\~cʛ i/K7 ća>O.X\y`a++^ h !5Mr孩34L*ͫMQd{ġs-Ź^2o\1p4ۂ`,sL?0\ -Y\cOWl>: u.FI! ͇ceCj4 KrI9^{r+lɦ@747`* yl-4Ay&s[g M|ޛrh 84 W44aDI!#MMi>˗sšiKdyϞ {M7х?~,a/m,#aϻvt MabGCS5 BB.6Zh^ MU,XC9Yh DhZ`'n<Om?>ㅶ0EK)g dmkm^>JNLe "ӆ>Ê s]҅Хd? MnN+[+ a@VetXkj(.9nh[NA}ToOZRzĶRn+sA[V()B%u lRpu. ]?LO3:BBCӧJ^1Ρ M֜8߁EgͺXd0evHBy8f߁ySVQ@Bs#;%mrLS<2ޮ$ vngyJ Oc JYF,%><ƗUL[1l؁%_Ա B  dnBjߡ]ǮTaQlVrLj[g Ja:;8k;+#m.{hz=BBBXilX99JD5UstOC98Fs"_OH'!YK#ƈV(*+xdxfs~iAjaw8h(3wegr t1@;mE6U*=4) $ǠBr`eR+:} v3jģ)ըqfhRwl(N5$yj14?c-dqMn{hUDC 7zf׺9u">^Dzj$.yUm^CLK2C@Eؾ=<,YF5]W[ #4WS'W );FHes]5l,9֦AZ]8fs}<~픤;]T*]=]^p?vL.; ͣe] Zwܠe[;fzy1 3$i MW|SC)BHn 奏d1|oCBsz b=!4q@]5b3h@ A`8/j.l OYSGAJXVfA~dAwk K 2?.ђl>{`gܾs3JocFh..L] !78ݝ[qHϚ.#.=zaP mӊ2 uH˻%*Nh2@ؼ&<#4CM $78N<ԹRYa9*H54%8)bvQF5MbG^UZSFshb?5L{hZ3<4s{Pf,0 懾TCӵB14-MB3p%&C]k+@m .%4L(=+4$C F M" 838& #.XjSb94S #LL2uVFyX\4CVe TZQYfVy[h3<4͚܄Y<|w(7I9(_-v@Pxhr ̈́G^}:I`"S&uh. s%2á)R짟!0K3GC3O'a:%2 |"].|4)46i`pBt,NATЄh!`q"QM?J])/GgZ)+yЄ3whmt͊l&fP0HXۼ,Qp00+Xtm MQ{}[hΡ榁Z!4u-M8Kh<Kȶ;el׹;:,iOޭ7Et~[hB!j~h.F" cDЋ[.yɔ~;L 7sd*LgO ffZ}|j$69]սA)kTΛ 0#)mi\ik~֒L֌xZY[CuMWA~+ vcu>; mt5]ߦDa&w␔뼬Sԛ"ʲ[h_VW&(8憾U,pIx/#z#z^5v x&ZqfhZU$7|H/H?ihxg%#h:G(EzvhF.w )NHL}.0;4AMBKI@)  /g14`rɈe|XФOP2'l*"} (qgsՀAD4DT6S ̃NŮUݼȵ jtuۼ,㱇&\h-?tPCtҭBs{@1 h h h h h hcY8?HO1 1BPAc!!Y:.3,c~p?EB &` 4:~YӫԴUY{?6iNhhW#o<꽽K_āzyWąWR(vk 40O2[[?'CK!1's#4#Mb6̼VG<~h}:&| _ B"4M6j>>4s2^YUZKu>QYkZ#2.zM_/YM[X|=!9ϵgaaMDު,W9YUznQZOVtQ )lti}WtOӬYb_ezt/SgۅwCZǜj'LeŲʶߩЎ+2vZtM`BFB3ir׀i߿5e܅fVb>]^fTepem3G 1<`M{;v|BS'].4O׾ &{l9N(/Lf-Ln17)7}oo mh$Ch qmׅ"v\4/̦qHbA<· UEF”+ឍ Y&{U lwU܈O5 ۟-nF)rIu(xބBj.=^Yۯ/x5[f}x6g{箣8 #Ah@"PQP:hAce&cg؋mDV}J ðh2 XhfXS+YhNRiaMxJWBy"Je -OMO 7XU&hzcf[bo4+]Gm}B̰!ruIjR*i ކZ-fG4cmq;&Gf0Vw:9sm\>&}#0 &0M#jE~uq3-1.JcnJP Q}Þ4 % f?x͕ilIqG͝C]w8bHd0F4? l/|w7K\uH1Ų?N'[k]}[9AdVDaMa^-THF4CtD(W4l5 _<c-=KxVuxP4?L5F?0 &0-Tqj2$8-G[o6h2|h9)~ьqn7T4M`[4C)/D4ayK.ւ(Xaߊuh&/jQGO4cK'ͩT򆑻o+]9ή]?0 &0L"? /4$rI9ic3rB D.ܢЬk$ MyZi3 xKyU"A8F4C@3_kί} fd"uLݷSQKb,aEaWb&fĨH %-%o-K$Ƌ2@4,m~,h?dӯ l&-Y%܅9'dD:$j{~MQ'IX'@:,g%vo;l [ ðh2 ? [+=Av,7· zFޓ2}_|yHxV:qe̎;ac5`,IENDB`pydantic-pydantic-ba0aa01/docs/img/logfire_span.png000066400000000000000000001143441517143232300224770ustar00rootroot00000000000000PNG  IHDR$:4X|PLTE"""***HHHΑx,+3ɜmD##"('&]]]&''/*(%%%۹5/,<2/ɏuȂ[F?k%$#/69R@:jYM>78ARuuukkjDDDnsWKYYY@@@duaR///fNCLak666D83:::fVNeplRRR̒xLLLbK@ċrdTWD=q_^}kzf[y_IAc4MU}ƩG[dm|gTTTx).0RkwpooobS-36}icLB)+,u׎hWUo}FWan`WqngyyyO>8ڣtaBQ[ˆpkZqrrWXV18Fr&'ɲ#^:L *s͐lHVӚE2x[C$o" " 'DH;vl@P%Ch\#3%$W"NepG$kS.kP|D O$MvI8"Y'%d-SΒsDrȆ7* 8G$羑mF3@HnmaI$(DR,kg3U" Ů&qIF P̔!B"AJ889t?IrK$ڇXk䵨<7њb5EDJX~{¿LnHrlz).^ّ|#|#岡N/lj=~r$[Ɨ85HNzeY t=`*kU:sDT7o]yGNTx=/"ySiۀ1Nφ4}u/t ʘi3TQTٟ4B^A&krjRJgTv/Iv{y$sh.e7-!H]ƒ}C'Iq-} <'fBo:`$ex ۠G2|DRɋ /G y6na$Tmd>v$ <'fd(Q\z:JF2o~]X1u] #\?DW$gwJG2wH;_JVx%kEL%"n4JEF y$I͢|E֘EfB |:\*Y1cI"9`8eM^kLiXi-r I$da#p$ҞzۼCFw'f` H蜈Ad`D G= 1yCF'Ec;ZjRtbݬ1kIjtXOHa&] mv ΀G1*|C$j Erbcv*g&aL[GѺ8v!]ǖ?otB`B/~>G2eah,i(d!8IJF^/BD [. ܾ2c=XoՅlH>KQ Iq>mm@'y_ Za~$QH*y3vQOpd& $E-EBFq"X \-yS3|oϼ9" AزmɣhblFx8sh&@I'(;xPP`شtv'} 8m$%Y´PT\ I^C+%ّg,Ɏ|CI Xg.<)zmh[)!mƽ\%~ wn 'I& D1HNb.}ZKbAĿF*;RGd> 3< w@W*}FJu ɰT f(<۷!:G,aF%Ȓ#rSI Gy_JbII~kRIgO"X`lmYi0;ގnen5koM Xc$u [" rIg0Q*?CCz~T'b&(D$Y ->pfc$ /K ; =)ҽG5'%))Z$HR/$dZznA UI` Cna;`I[︱EI >|KR|IZK%Y2$407kX1ABgg]$73&HK%Y*"ɽbs{u5 pܙ1rQ'$%u$@3<;UO&9|aIz\5lY#:C$dì]S@_ T:q:TJmtOJrOI~S"̕T}<~6vӸ$s!3\t BTu,cyIr$%i"I*䒜d$LXrG?m3WrT_NKYHK H"ܹw;s("$^`>$"C2\)d{,\K%r[D VZNT|iKQH6Rd Mv3dIJ B7@zǘȪȖNj\%\.{$hcGO5'֟щt$).}y.|#$A=DkI yMnI=c$$3L`u)BؑRn@$%YcݹJ^|_(i9<pP/YxhG$OųäQ"f8<l ($k|9-M{ pSS/}<ϒ)+&r 3Μ`(bz) IR ݜHR%/ _)m?=j7'm<=l 1I+k;W{IBU1G%YꟓftgFuU$Ũ%yg#C `cBt4IО+; T&A1IjMܓ 0} &SUCT4J.{R$9`Tt @VIRpF.I:k=M.{TڇpEp)-VyX$FҢ͝gW6ɯn KkgUq,d~\ n7Ij{ \_hΧ@G=4‘8IG[9>pfmo4S2IZEs X fvC$%Yvɫ}0RT$%'%d1_^}$SUu9*4YIvgYz?šS|V7]`6%M}ai,7Cɓdzk԰Pes N*I\tj>pf1F ӬĎm&EImUK]5d< K2^1j֕V\$ɌY?t$0‹H2$f`+630V}T]dzr\-Ý/IM$SOS`̂(BwQ&O^h{%NqdB>pfbK$$u.`Rf.p+$u~tHF$-zƨ).ݖ݋.$ǒ,Έ9IJ*WJ"t E:UbNHuHIV+ea!AZ١ch\$,m/i%$.:ߖzy兹-gIx$! $F+ɯtF?;ϹCLOTHYC!BOH$I!DR!>F6ʆB3j;Fw{"P\8^g= 7Fmy>.6$Sl6ZQ ׾zB"i,Fa$LLÑWfB!j…z"CܩH !N$$[8q[2Sht55 xlVFЂ]}9ɳ03H e悉iS!c98Z#=ʧ5#_Z2xJ_2]7AKY$1e̍*S!C;&=͡8}ۋ>rj$o:cp[ɘF~|QlvdmGHΩP]&Cs߮LHf<08V(IڐnP[hNHy4u ؖB% rZ]<'YNBB<#c`!N2c%kJ 02\k|4QDVl],SD:B<#d<<1yD%~BtOSe¡Bk6ϺLCiw(T"!NHxZ)Y$"E*pbTwOrN2xf9?olB%!UP.sr*Q-S!w>HfܼfeK]FRs‘G8'Pjm120e|r 0g߶(EलLɳDRUs$g _)<";rpSIxZrX2Ye2gSH.-Bdk[?,88 e$_,>H9+ch+8?sHNeЦH:må7ַT@o/7,|e1ėaeQ>Jku+D}d -",I0R|T$"O*.^ɺ^;,ay+vKUa;~$OHԲ|U(2On"b72 `R(Ьvva9~$B=RZ]H^҂l oBp'zr @YvoEhݴj<.[$xFhK将?tIeܐv߀VƦH^[JwAfI=*Bn(, I]ח" HqH |:H/Lh3w%[0q5d9Ze#H(@me{ d9`ɾ# Oo y,<#'mso(_'"'ݿr0R?ܿ+Hv@F/$m΀Dd(+ODGRww9d1Ia"7b\XIp$;Y˂ݒTw$%GGb'ǚ^/HqHvyO̯n #Dr) h?^ ](_*`=-rx\gѻlHU ' ]+ =Di$ S2!W*H7/IݦHS(kAJ!R3hM !MzlAĞzP EЃĻRŃ=xKo7&jަwDO3QphI>ofm*(?SdӔEEIZ [ZQv38$ RGRq[})ŧ2-96;qלᲂqަ3:Q!~uGbCɌIvN6W\8JP3̱IZC?PN$}@wM |K c $I_n[@f=m݇m\4^?_T*خѪ"+|l4O&2K2`Ha:WYR:l$YEYQps&5ۑ@A[#,H0q6%Ys^YK{?ƖHR$rCY|)7IIA2h$4$|x36,& i)&a$Iw"S5jy1Iҥnt'nĖ%y%BWaV"ؕ!7dfM7&02$’.AnOڪ)$9q@X^FIVkY%ɚ3 ఒil3ݑ$I[AgE}+CeM +|׭dyV쩾a"Io!$5=RfTI?Nc,,4IBF>*+A&$ ?\ \pVPhkmF! Vw 5\b2(1 ࠒtE&xqGe v' egˬ ?"Ig~N O:W'%$H2l$ *I6%TVHr*< (8$hw2ޕco/bI2%I=G7Ekk%Tk.0m̭?a Ӭ{H%;]Hf 2H6-K#9ap60 *:Zq˙$͌Aw/fh̒& Pc\$)9^nq;rSwR<$} ?Im0 5EI3)Ps%УU,M$=Jc$%6lDueR_bIvi UY4htIK~Icpx3Rz*!2\1^.>>^oluA#0EMn]\SIo0 )ɡ1ylɑUG`cI:ܗ3KCWH@ ]f ˾.t`uCt7.SC6IVtAi*U.cJCxaP$1H i $0$ OK#]*ItHXREɅwyi.1낆nlԫIA$~I)&8${<0 / ݘ0Q栍n[zU6.#Ln#f8zYlM-^_/EO>X n%4dsւ̒w^i6 ޟ;6$F!$y(G Ƽ8 +۵]蘒ù_f;XNmG| eSPuL/ r䒜XS݀#S3ע=[&J >`|CWbStބϋ>0 $\%g0hQyz_% ;&#j}JCI+yw4I% Z!i/F7\f]j-5Jl p (a8~I2 7${$p!D= J@Bҁ#iB\nҽف{pC߁/L@lsKS:~\H" D$I @$ H@uF2ʫ?gD$y#%X`6vH>J"ktTOi][ | <yg"DHJɂVH{-FʸFnAq^;}>Fd5ruLS`|?V:OY':Uuӵò4 逭9?ɪ\x^NY5"tw"v2ȜKx h)i9 p%/)LJ#?15j#i:fʺͤ+~ Ѻ!~@$Õy-m9xZ_?_/-DL/|j+Rv#-^dTk{ߥ癲=\*vl[:m%y/͔Q?(z6ᒹj 8R΢^@zI.&>C4s0OeIyIHYݸR#'u{NzkDǵ^})`+$,Z]$_'w+rz<<0vzjy>﹪|f>ݷ9#]l kXHęINu`HrDZ#F}! Vz#HY5E)8 d}1y#HҢHY @$H@" D$IXC$]OI @$@$|`~_8 _H1eD'+0PA5aQTDٲ Fna{j5ZujV>^U\ $F#IDd$"HY`$,%ÉzÍsI]|. 5*">"t!,b9 h}@DH~_$W+HIFIFHN *2|is$}-m9 aW&{G`{"_{P?DYo[b\s%>P(e6 3I͛P$= {W9?wqޛذj1{v1D6"9X$L-EO#"CNHɝH -ȏvgUI\mˉ-JH97UɃ-:#\I^iqsMd$lQDPHw" BKHL 3=7Rr%)c}iJO'%>"cXRU["nHW4RFt·$ylv6,5"0#鎉C%t$ UHbV0_匱zYE%+@Dv" ϕ@V8PYqH)7%1pF".+lm\ csADvHVeDD R<ܨW}')+7A{dg'72DILKJBڑcHy^^$uHjy|Q,Dq ڭE|et;v,8E?b2ő6H"-(o#"az,߮N#D̀f3[N6p-zilׇnh7o֍dX$"GSB;'oTE2xL' 'HHfr D"h0{_IwDPS}MoۗwG_ftlv$"HY`$,0DDI"" $F#IDd$"HY`$,0DDI"" $F#IDd$"HY`${qC$OՂ2 jC Ԍ vsBd\.@LC8΍ Y3#=mC{Χ=MB8H !B8H !IoFM+n8zFy 83VНF\.#< l;#` lW$ sVBX5Z9j{̣pϐzC 6u*WuS6'teA=Frlr]$q[ɡP:spXm?"ZɺkӉI]cI!T^="b3,cAFbf&zt{"ӭ,"iFYa䆕7UYy_<+k掽ݲP?6ƺ柌.LFhYaXoǔT$ۦ{ !i1T֗aIȑ#Io0`0 \{eIO <1)3VEot4d7/zxE 8 SEP$#Yw<4& 6&I$޵푬V/0{1Ha%(3(6F8u5v'ɟB/1L6z03?3\Z]MrJF"qV@sGXD_Լm$?2H7:lKHy&I9O#a5N).cgI_)FY<' (%7OH퐏uXwH")㖖d]hSܧ(|mq[# ]s}|sbPau5 pɅr_Y^x30ĝ7M <۠xH~A(qn=7(}޸zPZz*-:vDًRi:6JY%Wrgj{4nX) Ğ&Y(UY Sw{LGa]IڭB\`' I43,dR_$H [_|`|Ň`ӣБLfi@ɣFv:(cu+k?ҝ7]Hq<9ơx|>5IA*\ɿ{Grl`mV>Vqs$.ZVL-wI7F=}~ )6l $E?"I7(Z¢r5Gr9 !v펤UU_x?܃jʌž̌E) nYڛdxȣfAsSo[:kN b'n]#})f 4\78^eqC]oDqK%kod>]5:Un>+ !BBH$ŽDR!H$DR!H$DR!H$DR!H$DR!H$DM?bH3^^^@_p$X5VUx5Gھobx|qѥt#i]m=g !>F#9«:t#i]m=d !>&#H~țdNX 9/9TcnhUCcPFtbs< V"MMeUm$#G|$w/Mq?_k.Vt2_` ֢Ĭ 6k&IIu(R+t"EsiΞZ[a-s7Gw؈ BK_ a P:&zh>.|RX*WbkcUȌV۽ \q?9ȠEڢ)HSWmѺڈ<ёJ/H܈dW((BkPui,#yb~Muqgg*}Յ{A+ƌ)HJ+iבԧӀHfb7u$za+ҁ̑u$w@D2Xuf n)OEJBJsdCiPL/gX62y*++O'&xR Z$udɓP\ӑ=٘C$2X*^hcU(G_~90O,I]IȬ"Y+#نT[r6\G;(R&IcU(WYg@DN2x4>e]lU$[*'#(7S "HbQ~+rSC(=I @7"irt]"rA!HvAy$-}\M R#Y--Hrઁ#֗/_D|UHlg6{u7#Y(Ґ*fr*sd>HQDS"KRmV*RuUIǪH6Z3RVh/ڑDTur)FI"ȇHvw"-ZW_'PJ5#m]C$:&űH7RJ#ԩ-"JN?p뚝uخ ׯ ֒o_{-O M~~V=ZXۑl&nHH&3gm0)k,Qִn yV]ADC]E2(XHRt&Vi00rnNԫiFrΜv#eeΉ%0>,Ylp>keݙ59d#ZXItUuWgH:zeyMH^Y2;\dŚ;#٧)Q+?U_ :0fϫ]@eͪ9Qհ;+ Hΰ#9iQ`$I""F$F#ID䁑$"Hy`$<0DDI""$F#ID䁑$"Hy`$<0DDI""$F#ID#?F%>_S57 6D2Z 5NTЭڀZ#1Ğ;[X,W9y0]Dd*d4#O+$F=7Xq$NDXIY7/m3FZD2sDdy$ #"V/#tDr#{EVHlVF6EJlhF]s=[: ̡ٳgX|nspMgҘ𺡱7pOH[r"yM(*Fed$DI"[9umzFoo,낪pҎӢGp2̷h7\W5峂- fTUOD'uުfmR$ɊHKVJ$ |Z z(Sgx'H zz^A ܼKb$dF<0f[|M^O]Oj ]/ #T痁~͇aL9gd Xp8G|,`C$Khow|1AUdka3PLҧL{49\Q e3.I|r&Sk?D҈ `2'EjAD+Q@QJO5W! p<ֱh|spuZ I͙gb=xopqԸ|ֶ^7"yx9r{-6vE20)pui<(ƊLhH?]޳Zt(GhF4ի1 K0⨝|&y,+H@Dֱ+W>&uj?\WTHn5ME$}(Au=+֜;13r6$%DdM$XJ>vEK(ա?e|wNcf=_;'<4k+0Gz^ck+*>#6ukKzJ17Wi$\xfֈM.H0{Tq#| meDnhtS"+C*R3.$K2Jnv=B7\n,8`g;_~>z8HD#KHcIkuhj۪f?o' _uSoq] FnL7Yo߮FAvʥH>x$qPbe@<7u_y.= \:#٧_|"iSk~ֵ.[m`WݘNӧ]JV$kHQrjzG28/kN=REG8|=-Erj{/JIn\g#&oMn)Ez$qT: ]_/2ofV$%U MHu]yF7U}&ǫĭ_K֦ Xk֩M}SDGS$*DEhf򞡣Y dUuP==אv٩R8\B %:~I`?X졚Q"Kn"X_q]GADE`$JU|3,DTFM4y1#IDHe0DD.I""$ F#ID䂑$"rH`$\0DD.I""$ F#ID䂑$"rH`$\0DD.I""1ߤ3AL ]r1.aQ~`y!5V1ٰq]\b‚21,Ke ,yCr imh12$<~E+kIIcjI"y̪H75I_ofoH]dsYk4j܂a+Z+aACw1_$F+•U sK;G#L$V= 2DHnW3Hwr: 3ɭbT*BǤ9$<<(HtiN$sF;.ޟd}TD$y!.:I<;3)E:t}ԙEwe]Up$+V!~l"sbݑe! "tcW0" r#X_ߝdB+ECّ7HBB3m$C=*'lG# "B$'sJ"M?(56)tl$ vh"p1<"0^dpD$d޻ۏdBɎd1yc,"C4y"IoHHѮRun_kZo߅ߊMLTzG%1 uR$sG!Rq@@D^H265G^cޅb#_0K@9g?P{ F̆#pIj 8`̖ "/T$U0:l$: ) *}'#Ysd pBaWuy63MsX1iu"9G,y"yRfF򞞃W[l$SɼZ$w~Ւ "q^ʐg*1X!W$"2OEZF2amOV$mHEFd Y #,ّ3 Y$g{"2oE.FCE7HvN۷I%GcL$"y"Y- aD&E2w4"a,yeI5r |D ފ([l$1_vk)F[*#a8'fCH".Uy"Y}W?NdA~T$?w2亩 "OV$KUknKEk{آ~nd߀Ɣ"H6FE.2tbCulE("{Oh1* rdkUy,'F!!dl}j눌ݱkA%ObH[jR# (*nN"EcP J#H@:T:] (trem"ʥ{wCҊ^w#яGcB8X"y=;vg4zetTMDR-KKͯg܍c#SYѱ,[/Cx+IH,ҧ u&5Pyѩhl}ԮO G% U%[" m+i yBG@$ӳ{_A$HIA$ DrIA$ " I @$@"yD]XHz5_Q#y=mWn^[#yZbGr՚$k$nŎdæbGqbGR[G. \g[ʪ$bGrؑ`KƺU(k+cdӌ_8\wH+v$k%Y#Q#٘mջv$p$ ݇X1 _FܳOyfsE n" "Hc~^8MԡKa$Ivj֥upCHĠDc4ͬX(mHq*x|D|IA$Dod ɞO?0,!})NB~'vv D+$@$$D*W[{/a1JkysYsu)(ErbfffHH~]P"m)m~RmUϫ`{Z[V۷AIii8fH&zm]ZtH>__릞rR/*eI#ءC~~H1P)awt^Ϛ55u!,FH$SG8HU+b;|z؉duE\}7&& " `X#g#%7jމނ&ŵ#Z5DM'O `D"iWҳrGW/VHdC\NW5ߝ\zQHHz_k4!R:ɏjZg*/&UD@(ERbeK)eUڝlkHpT$}|դIWR}k^sR6Q5c$gaİLFykl"9ԋԦ#Yi^h7mi&HpM$|[MoFQF|$ H" >F,h#@$HHZǦo;@ 1dz0"1\ H^ ݠH ^LL` #8#"G"VO0$Y0}N H Z!tј꾿kHج)\Z ;Y?طCާ8Oij%\E& &5   mRm|vYZͯٯ"r+|=20Jγ- *D)]<6t40ң\[$~!{etL q ]rǻ6 *B17s^̑O~}), 'yk ]=,1FnPpPZ:L5F2V2.8{cMX/9zv< 펴fYBy?{H.VbuL#nW Z+$ fﱦ%^PL;k4#Q2Eog귛%CyWT<'")"@$w9lh[u{7u5IH~c]jg1&.~n131~n+i`lրGJ!gYDf"XFqaIYi@z5|I.H#%Rhj HDn(ToI%#"Itf!"Hy@D ERDd")"BYHP$EDV(":$CU"u"ِ$I 79W I$[I $.I$[I $ن$r%I$@HI@%&qEoH%iKaBB_Tገ"CZC1C" %WEEџs1n$=~}>pOr:kގL$}Vy0u֡_6bP<Z'}Jr$mĀ^HЯ?S7Zm@))+Q%Z\fIɃNK$N4n'>vE2H~75ґ/H6)/Ep}j5 +MٍkdǑlPg("9HFWVJvujmːuhn,3\^Pt: 'rI ȃu]#Eg03슻r#;r%#]I˙ǨT pٱP&ĠUgC?.ju#f#ɛRS_?z@b_)׮]HA"7cE2S'nE$Nhə7jKl(FD&qa@D4%LmK!FڊK258uM(ļ̮AL pebjƷ%$aQ,I]_",@x8J=cT*#霫7I% Z t]ɉH./G3J2R==pj*EGh@#kr Q')8I>&GR tj+X ~L߄uMaQ~Oҳ@-#XArJR.z,gÕ7Fyh65׭H37ƣ_Utom\QHN> wr"%BڠRC gD8rrd 4*FBYkb֪їa 6z9;5%x?(z>mp/sxnHfT7,%ꆛYmClb:( Lv#Ą5W$i4\s Sr: [?bF_ ,g$2"9g)%'S)_o"9}3/9oU/*$vd?E2aj?<@il:p x"W@D e$/X/"ҲU_随H@D g$/X)U*5W ">o _@  ܡ0Q,4Uzֶ]I" D $@I A$H")@IH$DR$ " I HA$E")@IH$DvkGksێqwoǮiqǟ7(ba"H j! [B:tP2d+$PpQJ -]@3*oaJ#2}>o./_ S""")"")"")"Eit[d HjAM#Y+lHa&#_"9μXEEӜ.gwJDG^KW<@΢$3u82dmKɀy01-0Oyߎ "b){"qZW\z|3]ƜAK# dc>I/ek3\b"b)" yǚaώDRVEIDVc8^BDlH>ݗcIERDD1JkQyMy *hXha)).AD [LrN.f?L3H$PI ")@A$E(HI " D ($@A$/ bHFl?: Ʌ 1"p= "4χ l&y=ls/z")z"ټ]DdfǺ >O'4@O$|2{\9̋X;$+9I`Hvf@$#rk'_y/"k晏7@$7`E$ " PIHD ($@A$ " PIH?k3Eܒ,$k! hYl.5DM" FUclЖ $ STUwZ/ Hkͽ ݬU|HN윙'`%+V`%+V`%+V.ɵPkE*-K6H6RWT E"by`O5) A *Fr8Ip#t)6lb88,݌R߰8C&* 蚥[mu+):O굥&R$7IrZϔd^^4#dHIx( kCg7G$MiI{m%$kA `ЦR IO36%|,^49PD,O7<:#BKk+I/$ir>$ߌ$$&IzXI O}m]um/7zz <${$ZDS>BrL&D4[L^ٺ^ilFh)$Ӟ4m)VSmC6!xzM44:OU۩L~s&]mKR. 9xQ"NMc|̉٩#?9 ZԓN#t,XΤV.5C}S&&$, \͜rz4$XZ"(NjC]ODͤ3Sb^#[},:=n>J5@q)X-_xqufMdSK;LX92,:<OH]UX A;n1qDhY4whl X$>G}[HB󞏤ωeŏ憻>WJ?=O IZ/d~*(9< O֑$EtjE1a?yT,h gU$S0Wgs}+?:Oup!NsK``E9m0V|JeJr [E`(^IfCOg0gif%h9ZW}T>IlAI ^cy(WTvFcȰZ ]C>}m=ʊ# ٔKdRBśrDMb^me=E%|=k^@)4r5P2G1qD>+GYbIgIZIF.=JDK_<!Z{OH$$R/IDt&= k(g2^ kX6Ă%Ǿ[ިazCEi:׈s7<bqU v j$]+#-;mJ!;cǚ6V ƁչXÎ+ɩ,e.}w;;mÈr:MCLhœ7Qm'P[XIćШ,(/}DJ}%*E.wKGCL'G5gdYr{v{%1UzJ2g12hąJ=ZR9Ą4g0 N(IyHrÉQszMPǀ)%" F֡1D`Iu7Uʬ2{Z$EI\s=IVt>p\$I>Q8vN ,Jj@uc])%]DO~HDI_;dd_\$XZ%'{#ɉ3ΖJR= b. &Sd]hDSKW(GEAHp,SZ3<Ѱ-fLv0pq.ٜ#߸ŖrbKEn%:?c./I-{٫ƆQUY$/x,!$`Est%PhKOuI`!Œ#a/_$镯ZI";DIr~x%/!h '&b,jJrbHIrG8눨tR@FWGHlm' %&&yvF94-n&.I_Ȼ%9 :ʪsVk I4';V ,  NyX@4X|xYMlDPs'ɁXm s8.7oufr5M2Q}$ĜLW=&.~ȝ宅$CZRV(I 1aG)?Bi$qIzf^ j$(EFHm`%ɿLg92_o}%m {juftŇw W)fcr.i H_, gV ?IJ^>Sdrn߈-f0dpS!EGɟ&ى$>+ YiiI0Z]$< NyJ_n$=ES\" AGϖ:7(A\fg/!ǿۗ)$$ d$,!'zۀd:Fu8nȦ]Fq{Iy{$Pڟ}w%\$^i1&b9߹ə1еb(f0č8څ$؏Hۧ5Wm ZL |m)2V<&LcIzku%~i(e)t0G<<.IOQPR6-Ca%) ᓆ$j֏HR($}%}]KϒŻҷga%9M&'ɉ$AƝAk>*)x$I#oiUHPvd QAIJ2F%ف zQ#bl}_I&zcmid7uT-}Wj`Dڪ4Cr*SDK7{ijSLs4T!.xѹyF( .I^w $Ei)NCk(9rF,dvPNrI w#|`chX$@U%aeZK$ZII~rdאwJwtgI*K';Cu&;O "q&#J*yU1_NtH ɤ#_I `K6](׃s$gȯ]=͈C଴3c D`!tn٧.sH,;e S.I^k> a]㕤 UJ*,X$ɓ'$LzMQkyBq^\{ޡPY3IN}w($pt|Yz*F':EDZ*.(kWUmͥQߣnӃ4#t8-@>iK<ETnA']8c-%l20iNO5%Njdm  FwAN2|.IQ0+I^ۤ)В\hŲ$O!1*=V;Fi (SHYM X %X1`milRBۀ=B"9g-WmIh-'NewYyjɖuy}_jHr@cC㴚DyZfW{'c2nPGF@$~I@$D I@$D I@$D I@$D I@$fN[0 ?$Cl@cVTM]Z0 ZغkTDź*u׺/ .(vp&uW$O HњaI" Kƶ5n;dxE2TUnvsdo^nDb0#IFVLήIw@W=gdstoxEry 0"H.m7,bh .[B- 1uzDrha қdW$=Fo:DD2׻#IUԑ|vpmml$?LZ|;tIku¼"Y d;u\2صhPMlӞH=l)xIh`D+$2ЊddO]lJrQGeY6mu+j 5jC+gnHۖih1%ОZLEa$uH~}_* IhA0=D"!3 AD`$s".55_d.B$5yn`TiErnJרF3]0dH0RE$eBSҝWrnݣI1KK=Hɓ0WQ;t7~kt.^*EI($b@3f({{"1D%:F'/ͽ^(<8%ZyYrYjoOݑtd )R 3-uٳg "F#) ` #]*]QJRZ{"#o<"Y]߹";j0ʎ0P:smP {mVwz)'Mrcf9(,oI^F29a;~^E|Q'S!}p$jnt-jxpG= uȅz0H&6T-n0DF2{HYgc`i?Բ#v>Na-ˍ$VZ!"l$P&zHew$sF9R): "*H$J?љوfA8T?*;dIHRRAD$#-q#Hz<DHz84I""F#ID䃑$"H`$|0DD>I""$F#ID䃑$"H`$+ O"YZR+) #o_DT\I$赣J"_}#'JH.~D@`@)H^UkH$Ƃ#I #3uM{||G$L4$"d=h:7wVmaW5HN fF(HoG:wtIke5 =ζyG``=HN˸a4:g7c\WMo$偡 a&Ob'*ѭJj]MT\mkYwٸنu'8VAG\!̡u}73$%*?-#}:^pfnG>WOXch>HNT:[$:z4.uWKEI灈PQ}"*?/f% 7‘ڇrQ鄑֮#ٷ}38"*?11R*jV֫ýG/&ar"튪7+,; ؖMa5#@$uH:ڮ;aYT́j>k]s?zLDEkV).^ jcٷHi&tHݶT.?bOH`<~}Qa$I""F$F#ID䁑$"Hy`$<0 *y`$I"H2D䁑d$#HF$"$#IDIF<0$y`$I"H2D䁑,^ݺUhį0| ~ e0FJE~ 2_kQ}{83ZzHsџQ~dgdlFib#)U$5~#a$+`$N$ID;ELDr3:D-F:'FDRHj*.$uRe)럭c!뉗+Ƨ}lY?@s'0v"#Yњ`IJcAh+C>XRd#_$}m1PP$+ׇK$g|$@@2a|Ulm =ڐKE&H -d2hh>XzR2\5XBMk /6=#*lM1TFHLzMqͅT?x5>Ni; {Td$父qoho $cGi4Nj<\/Zl6ڭMcGrhs`/3AXdO8*"Q$.ETZ4ǗESE h X.m rx @!b*7g͟]HR1b}jY؞Dr[.jpn󪉣]R .T=rNXt$$Fj|/TKS6sڭHL6  F"Y'3{d&:TuDCn G_N>jҒ3zU"GUb{_Lk+[IY7LC ܪl$.åQڃۯiiIDq/^^$GN$k‰&@䁑D)f{x{Iռ iOzmIo_#):<ۥ #+);kIhXɘLkxpQ@5M9rFd{g䢽hw]pi9( q]]$"zaGɒ#yC͂iw"9YKUs7ؖ V'Q +VHVYŒvu VHw$,7AHvȣvT{v#ƍ; 2jdoEosENk%uVCӑL!1B=%M7ɽb‘H>WҺs}Ha9Hhv$eD2;\E2kY%%֧O֓ȊL%G~;ɀ,[[Dpoh,C$K1ƒ͑RZ:+mS#yH5X L "nGq\K8yqqTS}ś"iVEWU2⭱i0DtHN4z0kC((\˶_|Mh@)iH>qP=<("SErUDfNeթ΋Oǟ߈k|e.б.[FZ:2#·̠ -{X\2 !9eǯYRWB"=uEo1dڟ IR\kTah+WD5d9hL,ђ>(JɻDAx'/_ 䬪eBVcٙvV[􄈢k~wEW 7>T?n>MH:(xZh4=s, Y#=\3[qY6>B@}U#I=g$_gg="yoVnɔvLD2Z$nAg E9"tX+x\52(+b&Ƀ(oHURC~5!:W$)hcOfm\u0Pޓ%QWnQm"6anzHI$SܲdH:՞C]JICN%!IȐ8`M"J'ȻKZyjrgh;:}yId`Z!e9pV`XZkX<; Wy|(#aׂv'H$޹w쐄#Bf8? Rjx4\r%d Vl;j ,7Hv\H%y$ \k[kz^sf{X Gr@~&\M1OHkq܂է#[,>5n;FRaS5r7%tJ3$!"!1HzÙN)8cmT8Sk_/qߖ/.Us_V?maGn@DBBqsU  El E Hh(""")"ERD$")"@ HP$ED(""IHERD$")"@ HP$ED(""IHERD$")"eEOZQ\S$d pi܆Q"=jb$|>99Q"iK$R +EnH_d:xTKx!\1;\T "0j4F@ /5oR*HD2{?׊HHHFt pYD +L'9xVh 0F6] [\#Jq^$yf'oܸ?@ YE 7=f"* |؝0%ipF|a{7B Ɩjbmv1Qu}"/H&yYDYSI ѻg0dӻކeD)i2ޓ44:I#O H&qnY ,zKm 7-318Y$o>yN"r;db$?`*\U!"eF0tÈ?$E"E.L-N#i]d Sv᪳h ->nI$E"!k&.F2pm0k UH$)"z$eRlqwp$Y+_$)"M$YT$EcdZ s^1}#1 ߾}{OcHH>\#&?H0F.;Vy$hGvHBDBb G27#0ˮ9259.WRM`nsC yl_9_OOOONI DOG\ $6IRsGHk:|Nʕ#d6\Cr"(q [ػc('0F$Ia2BHQH +E,Q_Fa_aB~_1_{>{v[q]tNIظb"嘲]w@ۦo1 7I I I I IgIy!>IENDB`pydantic-pydantic-ba0aa01/docs/img/pyrefly.png000066400000000000000000000756731517143232300215340ustar00rootroot00000000000000PNG  IHDRvҷsBIT|dtEXtSoftwaregnome-screenshot>-tEXtCreation TimeSun 05 Oct 2025 12:34:42 AM PDTn IDATxyxTw̙dI2L,@ b"kdeVҪ폶numvjmxQQ* BȚI0Y6Y&dHB& ~_0'g3gw9 %~k !}R>;(d?X*&kRdN-c;9szC$dE+QtK7ng󳯄^&%-%'a5EqATRQ{sדƄg(fo1/ܿ#/懝d$5:[WFu78-\:B܍1ڏ~W-l!Pj/0lΜCùx7 $ Jo>;]3>۸e+y*nz!nZґ=&̀F9;Ń n䩻5[?/XAL 8r^ YL\=i)U%`x"߳S<rl8.E2׊  5's[ :C=q~ E7 #EyG3PM8R JLD DgPHSjtCN, gIx cNI =No S#W༻y;2A3[s쥾֊zM-{K. h.dom+#"i CT[KˀcX6uE2$mn!ubrevA2~ gq9Tå.}+|5%l^/Tiq$ddF(v:vH_ےF*#76 h;Ȗ誶Lw#qFvWcŤJ^xf%qWnO_!Mndoyr^0ėSņntBbh)i(ajZG_qxj,X>?ѹ٘f[UD;l]FE41ZhoeNvՌӬԿYK3!9i޲Ura4hD3wˍczwͭC<}g-ަLGKF9)h:6ڊbݒOuawG~:RAAN'/;K0IT{ޥ"f)Gq~v`d׺ ,ɘLؔ>L̨䥥$nd3ϬA%+ř 3bȦ&G< r Frbl:7r#U4!ŽTUs\Mt{%FTQss3ܛzz]aQ2k,qQeܤoZ]-3:.ʘLĜy$> dcsj-1r|/Y[+!oӋ#1%w'*;DL(>?<.長Tw?6vTa1,8;=]6ŘnHӓYh(챗_2eˈuKCC}Hi;^ί#s|lՄOI9EC=ib%ovfC҉{~ wѐV/|K ۄ 0>h#9r^r]¤7ή j1^}Ǟᩜ3+f&<';3tӺ ^53C[ּXB y ?͘!Up]!KwP஥ 3)! o11;B2ArQ^C' ߅]6l"fM0%[~1m~? NL@s1*PFz>mJ2B"Zm~:BsӑQAGp*a]DC~+%,iOnpV*'4RiFuNٷo/!RtL63a\W?wzo˿4LI@u3;:/xg\WfnHTWoF!2VRѫHE}-nE:!2tusp!#pH;qUZAEekl♒Ex0g>Vƹe7-]7H*+zjq!צ\lמ @%3_1T2j ԗaTYά>xAVqOu뚷f ,*|` _- =۞NQc軳5/p,-o]'tWZ8P]Sv*CJBpL'~RG M V ȒL{z[w7`'}b~HD`gv?ʨݷ;`m0i(;n즡*iQn݉bdTmtϤAv_n{OJ#PUSwfKz[00(T3b~}>;ce-ITz˪$^a5n88^D0Ι惷qx5޷)`vxWAjC)y,tcS/¸ԍk):gDwĹiQύv*jCy|_&R:9ڽG3svy1ҀyeRr|zL0B*I ޾3˃T"Fۀ0zAaȸ_뱬騒K(u:pgwc\^7$Qoф~=[Rm_i C ZCbDn+n;`!+~ώٯYݾZRyIC"ItNSY lm%8kŶqKzL,߹ %тݶVډA+!'p9{e3d뛁:*1R㡾* ^>>ZAO! HJa)0 PǐJh* xZ[{ĕ2 d9E{˱X!>* AɈwxڋJqze2A=۔VPP{ް+qG\`o -f_7Za6ä,b$DX?S.(# >@IZ$j8թ+z;(NƲs#eSo/EҠ[ c4hv3D7vH~=R^ YXK]UW722qM%rU6Uzt oƔ8dnlnb-OiδU!TUDFPWI lk&<ĩߦvo9X(d1%vdjф+R6w-Eڡ),u+5m&wBԲ`,b3['x*]W%@f<_7j)wq F,U'hZTcZid$)kc\b`4EԪH}L!zϽiWƍ"& ؋i9=g;[hYixCփΌ:9i8[jzeb  I2iJuXFlToF1}#աC8b1exGO;फ=3 Bw/λI t$*!~BBGOZGkB˧#X}<|b^53œG::;WZ'*?Σ ;owMﲵBfܒY4đJ0.(h)YlG-=EHit!4m9ycw⫿]{! ١${ٮǹ ,TADžLʤ=~Wqn|yA˦4?x=eik]AZn;)G5qwen*C1oIK:GZ"uI!NBx>n^zˎ^D~o2"X4 ng#erˍjԋv/Z<Ͽc#sOfo-vUwD9?>#asW1+ fuNn~UMw L-Isl ʚGtV۝6,zCjvuNSMhG%mR Sn K[~ {ď y> 8;j;'^ %a4)8 jHm4VakM4:Rc8%ӈB, ޑ}-(H!~h-?-ϯg-op۝~wKKx{C?%n9TkgrcPGK:t~aOױpU篛<a=" HHHñ !Hm'*dtBJ} ք&FC{UγT+>Lm!= g^{ڬg58*.Fa41!`oUa;RRʊtk vSS~է&rX4]ȓ4FPJ\j>oS 6ߥ. hc' p  \!D`' p  Bv  W  \!D`' p8v i' A(uX+; b\AAKn`;M2d⥩cGl 4:OH.  pNX6`pQ{v)S$wA~H  \JعT\T["Ht!&  yuPkT(6\AAh聝IRR$8-8"  C1NED4RtRB  7N"dlP_/  0hg253gVX{uAA.AvӘ:9OE9VAap`'stSv  ,{v,SKH& c2{m-FAAةCRbAA.RLAA  !;AA+AA"AABNA !;AA+AA"AABNA 1W]T'#u}AܗLs"!I*p96IUmk-cU."k^0 ѠJCe+Vl:fdv}nű;G0Qf&c!NUm-͘Ǿj`2 :pw Adk={{l꓁|V)•i]QWi L#-8N#OP:)7U"،Η"9,?RF.M]FR󓷱 G pH rH1Sj㵍\=֙I̺HݓM8ҰeAn~Ck!g&V[ $&5=?e%!#U+%6Z"<%X Q "-gWח^DzU/h4xWSgZIqӭ<ŠoAdbJ&崵A>13n fփ4_om|WT-zi@IҡIMD+AМLwa&8Uo+t\ U IDAT;|{'%iܻ}w0ңNMD\Nq+ 509YT<2ueùC!JLD DgPHSg6E5u:cb KwI [NP ^Ä5K]#0W ^K#\*b"=%sV @MP`>R#V/-uI2Ҡ>Loߚ]Ek$3C￁M>''H:B~x)<-x3vRo ٰhG]ҝ5,G g6,~٩I+H6ұ!j-4B'4rd"rԩK]:2kF5pdu2~%zʲ&[¸-: ĭK 辰Ίot" ւ u2o*< % ޥAL=҅}oQ[gv)zL%ĨGipw-*gM M LƢ zj ?.UClSq&U:7PN@k=DeyVΐ~4BS H*9DƝ}-% dFI+H2 eġRp| قǴ)&`B#)B&2YwU)MnXߪ!)5hctZTв{7ֽսE\ Rфn+m5#z9ʧ=n214o"O`ױNTT۪hٵ ٘f[UD;g<.=iű՛ F\&/8iˏ)!`L~M@)kɝi_ ĵ̝(=>xXȨE45r 3ΗI0Usc|XBk[P?:{Vsͳ[zzm B-RxiWL$vИE=@\n,r5]FOWct~{+tYqrYMn;$ !iY&*gEr.9 X7H* @+ bWc욫 K!-yViո}Zʊ:u)PPRguM>*3yBUό&,&  K%jKPd_q߯%ɄQ\Oӟ+G&xbìTYLړD/ϤŃ͘Gt疗)CQ4c6Iϯ@#S+|{*wMc:꿷 >\ "s11"Dt)[W [ۆ̯r,gaZ2͎qtS"{zA#-XF ^mio7-"b\M4S?:ۛsgӈ!_zk'./G%>f">eVQ×޵s.qwPv꼷)sW3<8kNdJOuaD>cA .SaOF/e6kG aLT>g*+z/xYBTPTal &#N B;oK*[F.-רlM AʧA&j c۰~KLF:Z -ndVSaQwPbt~T&eO,Vb܄j;e מ٘JDnGb/^7Os5f`Ći ITHZk/u#5f/r!3n""[IY =VeV:ZAÖ=A=)jˬNhw4>nZ>/ ]9`Jle:9 v_nabT/:x-KfaS\U!5-|9D=|#C=lg+]A]'KNgQJx ʛKXLP ՟-]{uPDC_D>uNΤX2wu斞ƞA_9MiUh"+FU1y9|8_MD VuF^$=æ6S im;Q{Ep"c117ޣBo"(^Q\E{^= ]D8 (ɧB[.Zo1F׼r[qZ,h,YQuRBW4WV)x[MS~5楱86͝ = l8m0JZ-VU|27ΪcQ,bNRDAU$0mG 8{opA=c1 "~YA3/DJd3؇3g:Ŵb?RIf412(L[Etڀ,ɴG qϛ\~2ߪHxz|*  T pWX{fjq{8 U/+A)̀o:̂SR <D@@hٟg7WÔ)ٞc3LJ!,gFMgxY"1i]a᤼ Qj sF_=[[[@ r ŤI5^) 8k'ҝ^s8(͐(X(q~Ң(p(Ualc6ױp6wdԂ`T:=Z+,Gj*aqKԬUX9v}C7bp5!ӈ=1sq5<&\;I;{|3 CN t [QL}־Lͥ Դ;]Mӎr\=TՆRS@s߯؆V A{;n Yvgr6ӚOK@ Okn6?[@mN<]ծ:lgN˂_a}?/p9!h> ~ ZF_)}Pw6T4`O=p[]\M:v%`[r+$dM_%g8HaSF{B5!Ȝ9UM} G]L33jN[q"P2ޚ`;3 Wg;'{.Jd[HI~ 3VyBf-fv6D+;##h׊OUB T}/(Q'9pD i2S׍T@4-ܿ͟wUDAjp-!}$:',|66Y@K[NkŶq 3y;몚zA |J$DZ5"6 oCU{{)I?xA$?¥ZxsǞ]U'"1ӘFʉT F,e;!$^O0]~s%{0fK [yD@BV&F{7SͨQSGg6#s=9(4Uͯ$vj*Z}8Rm=Č w x63K#e4}X߻{; BW8ɄKU{7vVS~.t]Lx z\:KWb:}'_>7·#G9:K|9\"b\zdϞm4v FM':/UUj,C'Ʉq˳ N6 ѡM Ki{E;[hrbZӌDTF4t{fM5vRWF`1 430=,BGr+ Y*#2$~H1ݶ%h:1M=L~chj-_i^3Х']ә{A}KP|});e97tFL4KVZP"Ò+3U'qJ.s./ʥc2&%qyq#Ue-| &!KƤ7hA3.̣9,KaȞ((?\̡ 3:* 1L FhC;>D0Z%x@1<hظTΊebIg&=m:'F+;.z6Ҫ@Ğ[)b'GG#Q i֭s wQնofH߰#.m TOמ5qVDJVUy|zfA*6N^Dbro*΋wen#yb{UʶU)5RM(G# Wsj=o޽op6s`ҲwS힎mk:bL#>pR!A[xjLJ3X\ѷu~)n2|S ;k}ݴ Vaaܵyu@{ZޠܯÉA70}Ӊ"=4 ]N@D0]䋛p"8yHױݖMiʝ3魦hf̷&|)+fs??{!/nBZ}{ <_oUxx<367\O`٣>P#p2.u ;{m*^ݗrckYr6,>CObeǴc?;{Uw7vUG`ϋ/w9G"j<%ș]ÍxZ8'PpܕsuxnOC9`nNy<&\3:vxw#_Yo7/Ni<; 9r1LGXp@}̂0$$$ K F44Lȑn:NyTHh4m8lRhjT;Nk8s]>IoI͙u(pT9]ҠeBka~ֶ)2R0%zڪl$7|eFf̯).@**p6% 5(T mU8lg36`BmրW0Ж̱7V8såmkq!(\UxϳQ^di?fp=IFRR 8qVPW5_L)SP:ʨ+)xRM1p\8i2PF( Z$6t@llzE=< a$0N:o~-4B<(. ůo君Ažԅh=&f%Ɓ3VBlGϱ^0hP{Zv7kpe;AA+ąPCAAD`' p   쒒PAA+  7 9)9}o9#y\KKCZ+y<B ~/OS8Ub&ENibI^jR0POORF3ibWy>cs.6s$xY)xJ>"ct>lrkOޤ\&U 9Pnrr^l.h<ij)z֯>!+II7")ݯ4 Kih 族evR?ø3Ou~LdU,!v3m4:̡6)\`v#Oݭo;p;Yd79)=X ˞Mql85^EHU;G}&_Uo?uRq$R&'{U(Q6Qx 8KYx‚ l%6Z"<%X:+ʾngtG)3 h" {\vEDT0E Ur43i6+jfn\[n-RkΥmM`&$( #ny>=|yߟsFWx3a>W^F}?d[IQyqOvD;KQUG& b슍}6zmgwUiP`Kl|Qp~s7Г!}ävb :u IDATE^N➨aR5Ɵ ګ N-u%BYS;or̾ޮS_MM_0XF_%mPt/k]ϑNc{'b;Jy׵C8OMLrW_!ϰe:EJ3~=+y֑'ye|́2.jdX1VV2'#P\{Saꍋa'z7AoS#ګ-x*x\gCeݩq>̵ dM£SRUăA}׳|g&̉#~7r.K}xMnbd+{%DNjιĭd4p#ja 8tI(c_z ksGpL E#q-*ȥx^=K:JqN0q}"Sz+Nށ b\3)϶&Qbs ŠNTN8vh"gP ԕrvʊx$^_0QR6'z \ GP(ܼ\Qڪ;;>٫N# 4S7Py&m7%x$3c($;]Nf^$iӂ@w)i&vd'hsx]Emr&~A|]VOrtg"/#0a? wnrsLj]:y&QB&?HSyݟAsx45Ƶ/m4}w+D%RYJ }ՃCX+Ա9sG.WhRw]b=";F~YjDD7C1Inde*i/!K^]0W=9ь_@C I\]PlɥiF]iУ8ҿ3''ry¦"7)1 IM:rm||}3Jgpq'f$yr"]*[g?@*']D͛5۠|riQn;B]D6 }amSgiHeK.P:oK^δnr>x].U 7max dɇ-g9biwߴn%{~ƏdXW[jaXx?fD)?ˉ`s-x]q>5t +OY5scw`E/p ;9ogKvw."h;Q)'dJSPP!&z zk>ch'CZmכ*-Q+f]SUy3m-i{3(v/"T|Y~&cy׏8c3vJMBn $'T^R5(o_ JQӦefA%™b﹛umQFzP`)]E;ҍ|,%{=hFmwfݹ2綫D!SV2^xk+RAoJfp8@O,' z *PHaN)LSŽ)C`!PMA˻I޼7 tfA/v\jcf\? (8ٟr(>GCxR@/N өsĎkSyWv8(>32[E/-3f=/s eHgʿIm<2S|6iטþ9E+kٰWo90GرH*cOug꒫$ $ \zqHqNX qY.BQ9vR &lYM"r$ N@szf< ąA.Pζl+ E]^͠oM 3ﹾ\}.,2g3?9 ',.HhM5Ѕ+8e>!͙-IEI)EM &]𙱚S Xl dr: _$P|\\ !^~jjJ[~,f+Ku7/w06tǒy?'b$#f@sx 5\ &j3 q &hxr);[_N֨{C5I̙M{\]}Cov'D\av h0-zQ_ D 6nxa^`g8 (ڽX)xpϔNԔ9D=bnCe % rfՄbʘK]_@]O\%2V~)JK hDtW6%yxN<$7+EȪzOeQy30ޝ_*i2ZA7Xhf0JGG)-%{zM(VzGl= __/AS (PM&wd3Μ#]~Gy3C>=^Z_RGSQ^+qzG Ƒ!Tv]g;č13˙t:w]Ȭp(P93u`g =˖77tobU WD쌻3sKAb _{\Mw]×/V2o A_ 7=r0\G䌜:9n*_z}~[u[5XNj8Eۜ{FQg3=*Ewl>/tN°)76K'q7ޑ0CUuj,C۪ 8(?5ehhOcܵbHgWzqH ovqR(; ݍ;}t|mrsfuǺ91L}*3>Ϸ8kiC^ JmgϱV='2-v$ 'k9o'b7˘޶٩Ùd)]i4> Hнw7zVVS<bpKE[@a h s7(̖SJ r%LBF]Wk\QB׹ROQ1S&κZ3u(P9)ّ >L>핺dF \tW`pjb|f>ؓ{!_e1mia (ЌnsB˾r0-y Zæ hj~l՝Im~c&!M>T>ZR룄i=VP5c&H;Cq-fe#*wNJUaj "4Qu奘ɫR'tikӷ[~C[^I9shQ?} Oζ÷]AAVUm}?qUs7^tLJ6b^z:#"*p $tpD|Dl.7ruئaQ/JQoub-*j_倓; n8זS8#)ڧ/27Æ˅w6V@[2I+Ky,Rs,lR6O2ibU{H*1jcdIYG*m%aSHbp44(Ќy(/򶢻#2S|& 8&._i:'OS`{*@3l~6ʳWmN=qKmRga3q:%-wN%yd\65yv$-Ԙ}sx`re<.XHs-\Hr+Rg܋E߄H6pbs~_\ ^˘ge/Ky:bS8c),QU#X1 0}E5_gM:q'fƐwMsW8>!׵Ak LG7Gr{FϾ1yb,֋1S|&S$.0C6g5A7yZ ]1).MwvNAiw/+yJ3).9kSRHO3y?XHw'Ƴ0.]kI#lϪHB IVPU:v]~m[#?[NKva=\p["-~ׂi+h1邆ԝ\ 1TgۭZrGt^iH$]8~"^YWjqL D˧؊@y_I9Z&,*gu,z,Jv{NqÅu@+h޵ȐApM]̨ E(}3ZB^;[LINoO[:YAt)Vt#c^ݞGܸҭ03Nu=$9.!c ߣ({ #[]L{3[v"]-GFj+;Hvl~.>-!{:OyvP\{"fJf>D~s9R/YQ+N(!;`~󉉪{E-,0s9y_-ڪ/su5Xy۲'ɍf[<5ett !M~s47l|;,sM'HeL7r#ֲ$nm㶜(GǴ$CB|+bĥlb3sZX&O5==q)Xsצgy0˲]{$oy92/WpdK $nwQ`` .]d#C EwNS'Xw,tOR :RuřuEj(v63TVj\弃Sc ޭ  С5Ŷr-ή@MUIྮ rss B?ѭ)@}}TFsuA[hذa}]t'\pvQSVs5AAľ"2\׻B\j  /Xm4#pٸRIc\  9|)NJ94X0*"f'AA7:1x†P{AA{bA!?1 vwLL +SוFCHmr < s4rAjDž!;7X}eI![cOVPAw2>곰0u}]|h d>LCve?f\t{8׵NFD s}Uf\iZ{~[Ų(7>Gw{˩$YGc^]_L6ϭ"2g LGnjqjqPGfvj~x|.B\'!;@C,m3ә?|{vY2 ?\uўu;Ava꨹(!umg_~mQ[^`~z #v%vl0Z ^:!}*m|f~[2džPq:J $N%[\lHưP<> skOٙ6U"8m+q4p:{R~ÂR :}C%} 5q G~.o2=4F+]cӑ[&2* aq+E'7x3|n*fuC#z6: apf-O`h ~u՜/S?Aq~ϊޏÐu\X- JtݩcBܐ T<Ⱦ4]\5Q3 fjɻyu9{_8YJ uKmY$Ђ"CFcwWH`! 2#jSp n b_l cf(2(B ̗2Hvk #8&kq€>/O/&m:~Ԑ8pC5@u/IsH`ͣ.]k$= <VjIDAT\pp0`F]L_Yy}-4/$1+(kY8Ip`>c ++i)G-`ԝ+rgH/#vJ$Iǂ{O%g6i2'-GqqL;Ibn2m6O"ͬ#yDr[/.2L{Z.esx.D_XD`wO~ؕ_YX3 RO`9F2o'ZJÄ7*4(+ ٙ Q 7 8dnI{LL.[fw7W$Q2룈P9KRNj^Nz>AXqƵc_"ДOXܣYZ46X\ёy>e1k g7ҏX[5eٸYB/x.Ӟ8ƮE>1K7d RgW/`VG-wAl[}ɭ;W 9Ǧ+ga>hq ukM5Ka&#HܸpIv 9s3f.Fw:/IJX@;LEiHk6UZGK֑t[HDL,@52tgukbkx#Y_0Y _#ߜ|mt:7_e7"'$5Ç5E[Xd`$6=4Xpk,c7taܦy5ϭgL?ݝM֤}}:c݃%$q{1<9)t"F5QLg#X27WmZb_]҇0*v];o 6baֳ{#I K% _`ݺōÞdy =V] d! Xv ~0C蘆i6dIejWNJqQLHj`3KHzU6l Xn3AҪ7Ȃpsw *KX2۳[u1U6i C]Osm7?ccEtLJCdzbFҏf"7ddM"IHIMACIRH8m&‡0f&_J)7^G;efbIgh@g 'y3?Y]'+hlԑZV f\M5Xgy8V"$v=[J?.lw`l+SoSwܸ٫i3;WQٴ-m+6}wUU`r X+sIٹ+xv6Ri|)iGVIꗩb&@a׳hDHZ1=C׾FϞ7ZMHbk֓2s\o8^:Sh 5wiqVJ**9s  kdsdJA7)D r哓Jj%1V1.ZnZ-p ]1撸g.0?DUL ]Ǎej5`ӣ+j[@EEul&`2IV nznގ\?#֋H; YGsqZ!X"ꉄt'/ne,Ȑ)twܨ:4cf|RvqST榰+7] emec=ġX&?8zp/ZgQҢN*a7~.FL]Z92E?|6e+[V zb`';wO%FUQk,HܵqR?`rY~WCܴHBG;3s{=^;qp 0]hikjё~<۸)[stR@ 0бX02Yga\ -6V,6|J݊$>yms\O7['29rXMݟE0ةCv|^`T~Z,ѓ tN!4JS [.LeVmMp b,c7ybYAHn?Z $H.˩vU/B7nHvcA >HaG\}5`:?{$n j%vjCZykp** GZmh7g7hs;QBE+| i}ޓ#{|ycl= BjlfN[Pc֦׻<ܐtM&޵,A!@&L%vJ4POMlߟDzQ|tɉd|1\ىIg50vJ-bdc'H gEd`$[(} /`qsiàHb:J#Fz`;u8_g~rDKhx`~I5䔁fDhq*jL'ۤ&,*zpO4 _%}WOFXRVb;i_a:$R?84>aG ^mI aj9d܊z2(,/SGšf =I1 uw}߾>ئƂ$6a{t yO`݃HݤMEˮVr?~e,~x1%eѷѕlwbbg-%Zf7[c0yIGO&C"q͵`CGju[#KlKMg.8\n.wi Q_y *>7GO/TM*:z͍LWMlEֳ1+ʃ;/Kge;6|ٵw1tt|Fj ܜ;  ~j)LD3ç1~3O|(s9kf2-/nLv/. Յ_8PXOeL;r{P2 sy_BH@Wt*;$jxB_D+j@ؒMyR\ʆ8ıfbBjuG8 Ḯ6*(/n׊0PXC0@PG_\yIm6lȾX[ce.KS8EY̽YSUNvֽۭFsYt}7v-zo-'ޕ#lFwHH ܭlA cCA]Gi L+{RYKeL/|w[&q2j@EsŖ?|Y,z-b; ;A]-I$ݪ#Q7u֛?6xS$9j g_Ʈc[s4΄ :ܮ/l:>\Yef"z{yb1o5uŦ֢ DfI+\wp9w5ԗTR#u ܮw5"/k(¹KFqN"`<%\+ADJWp'r9V*ѥ/%#  tO'j}$Qꌬ^' /t~κZjj  M]PAA$  !D`' p  '~mذa}]AAŚ  w;.cR =n…v ޘ9wr}Q7j$ BtvwM6Uky{N  /wl`W[{k&Q2'ttzz\[K6LuLS{ ")r$mV?  :vBxn؜Ǫ SAԗRVʋ> 3BN6/&44ona8wSuĎ{x%<Χ26ғ/u^  ܞfj`měqU@E5taxFy_߮{L0a8 4w+9?Lyi'8 ljdKE r_F3?cƥGj+ Bg_.soda Бr0mt(ǏC3L6p Puއ DؔfV,2q@Ɠ3k /uAot,IZv_`zDDZ͜g dL1IEѨ}\p0Q{:ҽgX[>s*n8T"\`5 WRRCV.ueR91uN) B.H'a%#% }O֨D?Pߍ(+Gz>Il^6d֋->}Ǡ5+5:jM>x._ah CR>PNͰ7qcP 7qY :e F pbGn TSy4̀boLg(ȲIa4J7l UMR:E>>)˷ pۊ'. ElOed׶Pu ?o<]Sk ,x!%)ߎ&%B,DOA;C2v>)x2CNݱ="9۩Z7,ǒu/Qm1}$}ӯ:;*8C 4ƌG `Uj ,R_[GU)cI[RG|Ă pt`'D->M"Y[ɖJiv@k м3PZpPIv]$VVE\IN1zhj%3pn60)(]!AA1c&rZ8[>wst^ l,y6[WkwNyiP]6dƤޑ7đ`<@oXN~ArW][l4Gʽm/aV.-{eP,`+hy.[(e<S*qB%ԦWĂ ]0xN/vvke4P2j:x y7Re2L]tR U7o۲om?_Ư{-uh5E^gW:;:NH/dD343:hYI\xzy21*abbpWtJE.=<-87,_`_=NTAf[3GB.BCBla4^OBR3=@???>YQRR===\]]UFX;;jLkvdeeSDU;5=[c8Pr}PV5hpz?u[z=ai://*kTo`McAD0HfK<233bX2@?RYJhrfQjBY`Rw[J^W^7RK/cdcF[J]T1TzEDE:u86AE^LaI}B=@U\js=_D;FxAs~@>>>en;; k0IDATxMOQ o Hш$)!j$!*n]nܸi'eC;E[oӜܞ{n''S˲,˲,˲,˲CCV%+e-D,)e-[^imivoŲ%W*_yOn{,s>Dr<%/T$!$+8KeY> FBY^Ns/W+ˑ0yBG,ɇrV᝼r} /,kNN>"H~p]\hAW,k@iZkktQtN<7:…nZ/t ۫qಭދnz~B:uߘ}ŸM~FcvlʓF7kQ0U>OPu_S@z]5b3HzWVgeh<7+á~*,~[D$W+Qp^y'vdbT"~u;)em C0x"X#q':FgkS32uC䫄~=p".ddD"9cD6R3j_GZv˲$fw:ZpTeu`K*3m2 x5?.u07`j_  fG5l5ponB9RA8T:ZB_,2:<˰-dŶ $dR&# $c_%2|=U/oՁ)&K(SXfN %xZL^AM@Ų,ϧ}`; {#&p'fp"RfG<1}B r^ ?^e85؉#39\oկϣק:˲:<;gƣ61+8?k01彾[&Rp] [IaD`x*e2Ѕ[ueYa PTb<0g%j &;]]/Ϩ`$uΟ^o, @< @կΣ}U +v>@ce: $ Qx('Z9%0: C1;PWQSIJ19C e|LQ@&~|/O%K|UC!Q;PkOWө"<4*nCͩr:s\ <͂2IO5h,pLZ^!{,g%Jr3 O(W,W($-L`޲>`9iyss+Uvy?ylP*!>0pJPBBXaP]B|\[1 K"|>A#L3B!B!B!B!X\&;(Ӌ寑uGaA^y{w_߭[?BcAKaz1{tX~op VT"Z~r.x?b%ґqЋQ"FK/F8Z~x}!*88NGƯk'B|F[H$P5(n,*c luN[ ܽCgR4oM/'ܳjeOjM_CuYsc5Sz?Vp}ygy1w8#тK_2i!lhcD HgtEz~HNK20Zql v^<@iOp glI[Pg^.g@5W;!P~G;?H>>5,#z>6^|0΁Y W;!P~z/e98!@S|!Smtcr:B<% Diigp7.-ci1j" v<-&kߦ+Ei,r-cSK  'K@0ίM wjm6@}W:ԗQSb }+ֵ~^O0r9|ʹ ">P5؏#`$VfoޏPv-ɔV}ǿ {u`V!Qc Em:p~$DD B^ LY8nj{+hIbNF7Lӏ !DD/KE!CT i<;zkIDˮ-!"zf 'qdعIV'IHZr+Slx uv$po<:ΝF9C9%1.[@nLBq+=  /5X;d0T@tY|kMޠhZ1׏ռ&DDϭXńi `d#= I7j>F=w =Ip7 `)Ȃ(B_/'"z!QLvLs|2n P.JW/X-^[ PN)-`iBJqa1Yߕ_糳BDICLsLEK`@PH|x}k=&H y ,RBD4eg=P9`WRcl_`ZMu-ZCsBD4N: \l DwY䬗ᅮ'ȂrZ,DtE~sabgS$/1ρ &-Q0b^~!>5,#*t SjRe~Ѕ~1o :@ҞFŸF>`,&΁{!"zTR qud\0`NX3 h`;cXYsXJ'G?n" nJ^{vZDOKXM`"$\ YLIDʀu-M wQ<P_@sxVa͑InO~$ #DDϭ"e'0r ,2C1YIF."E - XC[es"ll`pSݑ@%b(+JRBKM(\8kM"ICxs8X4L ^Үg ~2M~$rm)ΖHHf$Xp~ȨZ錓Z8v("Rf@cPd@[#P,!"R>Bes)ӲhCl^ O쵉( 9}ƈDQn(ꃸ+ b-b1׺"uKR1"**?L+nz\q4;TT;U.З)6?V\叼Vc@83.֠yr ,ܪ3 p4UZFIk9^Qգ&Ts,ol@|?7bmJc@D-8!/%U/b<;bT{ `,w|^&ˍvuf3E@,E,HҬfu¦x/;^OqqYsfԷm)Wi7b'];f[ ^H^υ'K GhKeܣ:K vXՉlvxU:9ة5ȚA [ &U.;-'xk}ܦ탡YW̬@ܤ t`V`Y2p`Nw~޳ d_iHr,jxޘMuWUuoJ n'4b&V g30 M vϼಃ`t|Җ/t.G`FBUu\ɖGtW\w#juW&XU??S$@_ʮtR@ ]L0DL!b",N$$Rn-CЖʖV7[*+O O\~XysܗpT!3_s^o21\SUd`>E Li/c%K!*)A7 d+uc%5m6/\y] Z s9Ksk^q_c^!L-vKz cKf|Xʿ5P~$?W> 1FF:*ޖ7FKQ0| c.;dɏ FhȬfd2نJvKA.iKoz Qc.sK˺ @lʛӂ;m^%郌SBzceY@Y}vHo;xL>!c<_5~r !Nc=bc810zYׁ1Bc1c1c1v)sI xAO VQƜ42dHtÞzw{~a0Ec-txFdbQ0pCxzUx8AiB|g-όuLeΜh~5gxU ۼQ3Mnz3%qkC 8F+=RoϓB6sl;vu/F.r=H7 ˈ3x$f뀢1`,6' adأ_4bFo%xc +)H޸}:JLzᚶ +2^tzBw"W·;4|j4@VDxpv9i\46Fcc'HÍ6غ2E57iZG$v_Ṉ;\';3.ݞ/f(A&SZLx6`vpj3)pWn={SO, +VB3ԅW@5[4䐦5gz¶F#f{XhӲtb#hNk'ވ O<z.zŞP5{ܞg0+3Ǫⷦah=2^Yt]0VhIS@,)ȔLLV4/TJi fUPce1%ON+ E-z ZAq<- kHoli JJY_cy`wxZdr8Ci_ mɤQ=<4hettJ.2. p3ղDbˍc[VPd=u4Zη_k9Aq8c|D"$tDH&NK=sWxBsƹ̓PҾZVZg M5EJ®.%/ʬ cfUu{Q93k3a3f3Glp/?:A`p.4RSHsjdAިcBHCUuag>Ʃ ̽x@*fm{sjGƉ E`"3j' Bxfpp ;Y?~ѫ*EhȀ ߎ8VC[a{>Oχ S 0UBo:9EiO!ZO?!8lҤIGyw JS*7rSsMeN BHC`,{S:Vu[=y=i=m#ɼnzs: 0d3GV6ot ;00ێaJuq $ǁCős~8X%x\R~tV!㫃o?}[dyr1k=y=ݟi=m+ !>Е_z3hWi'WV`rapV5Ul'|xp@y3="2u Em%B_2=᠞縞쏃WOg1꛺P,zplȏ ML[, q}@uOauϙ7WʏtIh C̵lWbB-q>Z"˃禧#$pnl{֧xQ!&携%L&d6, %/o몥x)ݟ)!=_~6S4%\] uhJ_lPLǧ*zVɩCwl_)-C,. lϋ,' {AdW!딐;j}Cxe)ݟԓe!˘ّ̄:C5 hE>UML&kaDqEݺk yu_LeG _v̇E= Tdy̩ }<{ֽ>@CW@@ֺr|BT9'WOtROڨqr21<8:flƜhҲ@͊p}[+/ _Jhp5؍Ǐz'ݴٻ%0Oͥ앢=荽htMˈp$-2.*ڊ6,z3ѱL\$Ι:oDxcEɗDv"ذ4[uGNck S̶zV9Kձs\+P-)DQ'zV߭_!pw_qs@auE;{p y.]M?K;{yPx1Il P4^?M,#s>'ETS޻_Qgm͞ /ȑOܝq@xȪTr^f{Fܻ ๤H7rh4@\Zk#_&;dϫQ,;@TƩG@ h `RtҶ?;!iYg@$yٽ(yNh v#_}*_k$bze -s;Jqw|yrhܲ{'|H g= =QW ^!t7u%)X͛ H g#gBRi)лAW3ٸY[ 0jQSFx(@`;)"-[oU O'&&RxKect.rN>rM)ia@NKiXV(^S'Cq` `L=0 aZ˝ʤv)K;vl#{=n4i;1_Nk Z0bQGX?gVK#]K5own`6 oSueS' qfFK?lx_6;1yfGY@Y0>wǮT^ ,w+W$y~I$0ZF^j0[oh"a3ZUkɨ%57C}Ncw}z9;GG9zHYO7ݟ7A@{zT3‘`n7y/S8)705x5w|oT} яGOaǧX$mBPQRovh[F7oZhq7)*d9I u}^lcSĨt%/yoI72rN!ID<ѰJ7i˜y,3|7I:ȍ{4ü2 ݡ #D ͂w_|?@ X-L|d~} `cQl!fGݮ w;A &Y٩\W8:@YI()QJ)U'-ql}ht1REpI4 îRN/=D)nu`g= ` kϓζ@)j]"_{5ʰ %`d@)o͓(TTP#i[&F-4gЙc{^[J9"6s)wY Zp&\?(2J[_ݡvP)U/]d^9G/&9MWɪ DFD, \pZѦұ-ff邊RF9ڈ@v[1,*dFRu;Xw8g'l"d8dKiohBbr ) M8TmQ BպtXnOư+'z^C==86 v-)9D]%-\ɹ@C[+~7tICA6I\ A  Y $pmk; ;ISN3s}Z@OpWnPy4ND׳.}{ {p_S:vh.dZ7/<[C` jj;@p@fL@<ZN{Ynv_K;wDax5$Dk'FXVPR G@T!Ԕ \+P3<ݷx ;@-@ZTKj P-%s6m u@D&(Clm tz߈6m0M "Un Pu56,r[w>(}m _^۷(ur"".or[tWs7o(r8w PG&۫o'ARa#lKo%%,9F""&?Y¡\Ɩ"%SONA)Úe-#@"߁p$%KL:6'2bnz*V} Cȑz(26Bd+3&$/`! ]2:!e[®SHn5pN%#^Ƣ5[A>>C'&(YQ7|D0n7(nZOer\ƘEǷ5U*tOGrNb]D.µ0Q\,E9qzHJJrF*=F)8\nu"$3D7*ɰӪWa?fEM0%.&Vʗ:?rvtćdi_#)8Pgsl{v>}hN%;>cQ{)"|Y^#h,^7[$[zw(}CjM6Ynv~vQZRy7I/w|cy: ivRXM4O*Y\1/ŗbҤ3l1YS%Н#dR-MO_lM)~*_G$]H_goZLnryYhg.K]ى _CKt.yC*=61~qgcAk.]x1y{L#*˜mm]κj3='8lMY3O|v~r!Z8Byq\t X7r}&5)qܱC<Ȼv 9li9$S;^7J盈X("2cC]|^7[uQ%*6;oQ ] /vV:JO$Wj1\&|j>y*I-w Yws7PzN;{D7JK PcԱn!+O=Uct↉t+s1b@q⎜{':7VsM&η>=[R}7%H m8qwDBU:_X;_ja+ww?9_yTRP&#F{ HoAھb}療bAX!bVg,p7]Ω,1&L8⤰TR0{>" [wNz_1ޝ(+.P)[^y_-A璸j*:΃rBI:NM(U_G5Su[Kz?L\Wv[ŏrT!}sd=<-%˲'} ?y}b}H_Skg3?=uOɻ==#\Լ):\w[5;mjia{ғ<9&:< XחtΧy=>ѓ-t;Og:^di#WZw j?'2Vw- .2~nHBӍ{T#P">sai7skmsZjPRjR"jPqoL!~ 7sҒ{T~;o1ki~C:yHU!nԹEGsK}<_9cC,sR,O}" !}=gLt9vC[K,'v:_yN]Ijst\3*-ҹ6Jܢ>uOݳ3 ܹ5hJ=9|·D╃#?UwNiyRK˴YA's-;'"ܤ-[$ -<͗ih_@?rxz" 9#Ht')is'Sˍ1+fl$uaaU`Rsqw,h)sI|ηӚ?f~FՀ{ԕVH(=-AߢEHٜ4 zAhP hƇ%ĉĂ&=^Ȑq~%Myn -rl{WsDJdS69By5*+g>\|nɮA}i}Q?n/+pڔOxqECp\U?ޢ;jhBzNmWD%A=GIs$@ϑd=GI*!=y]Grϱ}G螧-Yq)疟h7irV6so{zs_msk=uI9oݸ496_b{hI՘wVvx+#Z!FFT!fqir,sD+D|3:2)9KCϑ!b,n)M=G_5 O*/P.M[oAsK^W|)&R*_zs8~N4 2$Pu)6w( dA"z$9 H2#x>h<:L1洴A?Wf rA=G=aږ\TyK`|r7<_<&M-yp URnځB`W{G;r4"?Yt|\٥t"RZ\&aRO=?Ph!xROFQA Ң-ai~*~9C7Vdez=\ hRY@EOτd=vOqAvK7'\#wyܴ4 ZCϕ77`k[E-โ-oq,esgP0.@.ȡb?y^I=U!wb?t)@:z5+5Z'3+p9bJɴ=i{W<(-Ei?9 eiN@--E+\@d@Mp;i%(/$Luec)w a??5׬&߷.g0;mH!Mϭ.<*|{>U&wΠߤ5{բ9Y{N)^u ϿE/z.mgzlgԢ@5nBSW6V`<6-*Obw-H5lK%2 Hvsv؞su:`d_s.kАXRϩ]GbZZ 7o r'oɃK7b?IzyE4338m c<PIq{ڶmNuJusGSV4@<Ҹ-d,_K%\ԙ , ^=9N,@ܒMs6Gq7]+KaP(aGxp]Mw*}=z^{WǓQ/Z@s97}@s97}@s97}@s97}Uה(AEKHEsJ4 RCpD):36ja9v]y558pJ -պ^ƴ7= e^g5EOF%bՎtq3bόQ;Y4̇*F ;5[lnR~|q\#ٝ)ewܓ>أ;tz,{Z:9,ڲug4GER+ĥCWߏ#+6*9ʻX znuư`̡q py:^9Рf-zTf]WUK:pКIKoLN͕6OS;^xn3ޅΏ[5ɹ`qjPC8!>Ri·!@k# sKLo;T-BR5vUyzFzn|dW]OKoΓS,AWyB-cZICvmh񋓴q<󗧲sγsAKrإ3z9g0,h:kykqeTy9ϻ79dE;? F>G2X^9{=\r.V-H Ù[0.2u'ts.B~ު08g9QA63uish0wn[t΋hbSE_Zyl$ܢ7 [:@PJY\%#M=먩::zLxJסuu(_omW;_;9Psʝ`w~ziôwVJKI(ȮvMJ1W4-:Jx?d "Kb8.(')rrr*=Qx``^U)eIU}vL1`]};Z2=ZC<9r;d<@LQY19ѹƖzzz.Hw/>j,gLRlgAm;L@:xB-GܣegfPeʿk՟fdOKkF-t5Q{g)5eXE;ZLNTpQɻOSeB=3-ÃKfuMmE}J'vwwf?GeYPI7,2y|z[pDA]YxzVAtʮQbz#2Y|2Wĕan:%eqܴyUuؘLrmVN۸tw^-kYW|ԩtU2Uir̗4IgȥKɻze҈v IDATxAHaءQOҘx$^AfԚFacm˃Y*E0:( %(Ä,APԈ=w<^M7a<<CYxCE Gr/9#}%쫠xVv8<[d<ҟxbaL{ ,=VچEzdłqC~SHP;J[˳NWdw 52r 7DZ]X)h7n}q9ZwBLq*/-zkjZK)rd=iΚtd58%˒ԭlhb`WJlvJCi8Qb XB;vC*km[%>G??$ |6;['˱ŚlBm~@HǴKN*#aN+yu;~6o\ɔij8nn>91LEE r}n{Wk+,F$HT`fи^llE/9n1G ̤6->9ɔ1;'l=*|չX6>隓>/{-1s~rʚcϋtBN7qSxQMlKk>VsMƮp 1TvtߙU9#P!!0_u>8DCE Gr/9#}%tL,hYZmZ:xcǠMDa{H@ pYL!e蹚 G%ܔD `!IDiN0K 8!C%(D(wI/1hir0x0x0x4y3p#@π9h43C _CqNs簅x!6{.G)Q\ q[Oflw#FG4E\cpO)?9=pAk_Y'}kAMCl{|iE*Wȫ^9wjIچ`EcDZ9s$j H """"""""""""""""""""""""""""""""""o'@w .%شyVz]m9n cH丐+ǕOv,{ߺެ7 ;!8 `XM7:Ru*ué2M9n0jD tz۝TfAs *]DQׯ*d}Wnǟ^^ulכ-y/<L~ ۑB2WYsx4 H',Jƀ%3O/vzyԒ[jnVs}j'h}&Ec0l Vp'>EV$J2aoZ:fq3e$L&i(9}v˶~=8:_8.`[0Zϐ0|G)HêAyvCHs^/8OދSs q^$8Z"Aίob6b2à; j&ǡ!z\9~s3B/s|wwD\uEi_ut]}8rE?ʼw޽#g]_o†H#"`:R(A:^ձe6fYZOBTGJL̗E 8)Y q^/aTS)@ꐎ9=X! P8#Ց ŵ0\tlbTc*$̟3O:zW]ϱ `g=&Բ?c]TGJ,. #f&Ac~+)5jvoq:F3nl .U#VHuq_;&[Iجau=x+WL?P3XǝVR(276vTppKǹX Y'?!6۠kB :8!rXG^pzl~ "쥣R):Dbcx ";m$:b8EFGMEDFuL ;0RdMR!5׎DGuEu,^V_+RCQB3 y㕫*Q6Q]qVlL vVeֹ-Fg2|gl, h9 :m*Hd5hS_: 3h4ՠnG ZĖ&c)_9>e ؇p1<^3'g;}N˗J%oMK@Yf;P$Kݙ&GJ,Ý)UK鸛j)t)l=ů VqXt,+ױXDŽW}ly{NGMTm^YGCkt^ens U%Z JX* 1lc)1K\ -ڋ\NJZ{T&FPgtNwFo_8aB,-Z| IMRω!cEogrZM -[zI{F zK9!eǩϧDcPY=5vU*EiRTcҥWGǑf~Jt|{_^ыGɽgMv$X[T45SѱQБkU7src\V0/.#k'9iҟ̒Z4WkisaX )Fk~]֛~t԰%C4sAG{o^LQr2W^>so3KS}vyu1 tM@ :~gGz={_ު)Ջ~w~7+qȏ@>Uo@ {C%-3ͻo[2Y'AKn~;j)'+<ک,8=u6@'tMri6~jl9NB@7 :KՃOjΗ9LU\_Rg;sk֋πb8YsP #ipҶ {Utnh;Ӣs|'᳉u4al(n]JGn+G:Bل}5XG\&KFXgb˚xs$TSgJ9i-z9*)!L%eGV ח_PR4yl\LQ(!ёoKHGP׶{L"藀އ:#Pf5% dr*@+{xã#1a:^b%KviE< .$~;^h:[u$K1+ًc׎;x /O!֐mwq.[KѶ[HZ;V/EADž(g0M>$NB:bq>s 6W: N4{v?ky W&m^ ,5tb6:ҩ׎b"?{G6C#-[/rէKN|3ANj߫ Q k箇Z$^;~$MGM/J]u+(N)vH^1ꃝհyȼis_NX 'zJHgoR^s0\GH$XQ#Ԅ<)tUx[4wV wW)tD {!*fzo?ElZo%ΎΓ"OHsMh=h}gF8i),%V 3ͫ#SgUg^!#i/Zg mį@Sߏe_bVXYS(J4zO\w TGʆ!:Y-Ow [Nmu#TGJ]{yUH*~GTGJle+ awakҝq%>9d.mٯW|H-cq0=6uԘ j8L{H<2UБV"::{dA5>'+3A!sP NyTGJleX +n:4?9fᐹE:*"*Kk?K67ܸH ]LVSK֢+`hGK"~Hx->F.t}FLcqjr\Vl4]-ۓb ]:8K"(/ ZK3w6&eE$ܦ V"@aߪ8둥9B:@})wپ!:mhꨫH z:|²F~5:Tr JG\$.Țt@&,cLfeȳ8aDUǮԆ:1"-ʹcU阅=XA#1hD֠#E:Y,9UsHnd8`L $gc WU43}#yNj2htB#젡qB"am7B u14@(hHaH=I% D>>:s>rSRzώ{M1Q\¿(_ $Ϡ }CGG%D_DŽ?PGF :cmKjCu2n%3DGW߷'d!hPs5$,j:6Ugӑ!n`$2 .?r ۡ7ZY yKWoĵ[Z`ɆCgnCbA갟j%cQpDcJHV9`WIG&Jz *Wg-;0Cc#׳HVqר\k Fބ.F'wqXm&!.{Qk7+p"7Q8ĸ'$#uUx#4(H"o :r5Df1A;!_4WFXoNɸ?C|q}-v*DG"u#Pg@vfe ec#!6-X_£#'ؖd"xوQXFnqj=LG(,bXW Cԑ5p.m?0kx\ 7RӴv&t$緡4WUo4Ae7Rk Ftj81DPB;`ia>b<Ɓ=qJkg睭\h}Q.bVGi\:`Xԑӧn?llr:[dn'SgjH(A^X?cqzmW6\L"A!2Yx>WdgӑH7A vb=:vNG_+S˲"YQvao'6O@BɫR׀fOVN|T I|nfFb+E0P)@uPՑB TG E0P)@uPՑB TG E0P)@uPՑB 1㵔5(qt# Ց(,TG:PBBu: # Ց(,TG:P{–vuqܱKQq:Z\"hujpp0Ztpp kp"xp"A5d!A-(C x)tJ 8nr\NAwr ۽ozqr\R99ߐõʸ{AC_V}}h{ZpݼM{91먘cK6Rcń߬'J;Gg:FyorY%GqeuG]#(r~:"9WqViwhΣ8U,rcR-WSij87wN_nk4G'p٬GrA(9HA(9HA(9HAXh1111111Ş( qK4Ij"oajtew[]Dب!7tbQI ƅt; &^TD~?Iû=n;o); F(, (o4¢ F(, (o4¢#n #+UAA_:4NG(-v,/~/na'5~lsD(Q8fJ2Q8H=G5BrAKä?/}Ͼrsl?hWMw wc_Zia^t,e=[Ꚉ硔y1TeU=:XNG(Fyg8*V[[%QXl[g-wGyia'̟םO94n BSz㲥Qs(|p1OV#G(1<79x*A(ܞO9(ݏrI=_($LYs*?MxljWQƂT%nجB9>=xp*Z3NU0pLǏT?榅8I-q <&UMR!H哇7P h%Ⱥ#+&8vU_UNקq;In*+#r^;&:o]G(t<6ì[gGvV朎X8qc(aٱ;Zuc/ .:TZ=ΎiPG(DoGNmUA zy"]uc_XQ˽~z*o{kno(v1Xv߬q |i*KӲbN߃8Bѿ={q" F(, (o4¢ F^a ?::IENDB`pydantic-pydantic-ba0aa01/docs/img/vs_code_03.png000066400000000000000000000223001517143232300217410ustar00rootroot00000000000000PNG  IHDR:PLTE%%&,,-!+4..!''(EEE445%$ 01aɯ)$$$)B/$#..8[ƚ;#"qRP$.L*,3QMA%%54E,+s36>!!=R!"X./G^>.*3Uqz(Amvs4K\ĤF3,@_M0)Ys:-0?z7Kƹ/akMI8[u(,v3Mn'.`-7s?SgLADoèǻCbV_Lj2A4Myzl+6inS806.rzQ "G'4:Q2M2k]Č'9\ï=}{]{K3=G9jKhX얷ޅnXP<(8B"Wv?Bo6Z0?~+XrF8J#G쾅3PvH{LǾơ}rg9O6Nk'+jh^JJ{=wZ=@Trèw`F=\eEhc5UWV,󊡴-D~V?fV{ysuxԪmxtvUzu\Wovp=:faXj]5RC^j@XaRb^QHޒ9k&tĉi<=nZɯuc20ger+66>!IDATxIqb)c1"@"Dh~xMx/AD1u* F^CJ"BEu mF}!\}y_g"Q(twZ&sYEKix$cӑ۸cA91֦.EQrլD-^4ޛȏHDx:f?Ӹ'G<ơFQ:]~I=ݾsFOC_sݚ^!pew]~\@x<.EU? )-'BA*GyR8cw,#/_/,-yryY6^N)xO^bē${]J*>L\ZQ4. ]hשǹ#٭p4c=Og0ŖȭUqIvqA]mܸ5r]qKf^/,>m݈qO|;g}IO_#\1x 6VF{;94DChF#j^ԛ;-[/4nd"~y|7J^H"~#N/Y*GWDaܬ$fqNW]~qk/ŚG%wKN1gˍ덫Y\sJ͍[Jk!;s*|StU)٭&84x[guYjp4d[3<}mv^kƕ"V("dѐ3&xPG3VF6kAgck5ggC<<yT^E/79Qʠp9obMÏ*F,JZbw}jc^ 73!\6^s(kǬC=ŚyTکg\BAjX;n^bģ$5&hyd.ϲ]HhC߭DhMS{?7KXO5/tz<{X7:Z+<"sC夶Z'NN&,=7;2G켎q:>w*R#>e3]0ȹzMh<9@_175_GHp˩N l|\6V$XqbMJg Cqh|b0ZeljHYsV~㯿m S]BPWSlP:$smOʙܦ 'dzbLCm@yq(Ϋq4[Cvhۡqp27(en<0PCFoYP*g7Πqpƕ|C$RM|ߤY_4놻B)lh}4;56E0&cp3\ [1 %BԒmbS oqpƥ,>!# oRGƇIơ"X7Os&TZEm3o`7'{q-z]mbuupJz{kmZ.V\7J h]*J {{wh* ւۡqp;4n84ATsww|} Wo W>%4[]K͹ٶ<54> %~\)unw]'e/G] ?q(c=}M<ԣHhK uoS<CZ!| Fz^{!Fl {gTquswsC=HbÈQVH 7G$Fr9>ư=CPГOBOso̮K-3;| 0NCGx 'w:uq`VRm0zB?~3^Wm0N{N='IWj{Nb^׵jq^~v^7j5^׵Y[T Y'ڒd[ #s4"#KRm0nvNL'VjW6l6V[~aΉW &YvjѬnnKDMe]^K*KՃb7`ė`|u lu}#s>1.ǻ?a;VϸNɤz=Hr}E)C;nXyQXe{q,89)gȍA[,5p"b^4GnZz <-c> r:ƈyʖ+1Gc%M(Mt<>n+:!K | lh!z9"|Y2,^b> z8: e1*̾6 ed\AӴrYq1 #}t^1%]EÁi&ZLu|K@CŨDh *>C|AOm}ZL}Sg-Z%=DX3@g<€WG9x`d|k L9w|!v>O#ſ("ב̤!=z\tÑKMn=:ѭGl^&߄ty7wPb~;BKʞ;#af٧!Ir=qoWy|(_V ziq]d̉ΗE}yZ*:)DʜzR+,QVZD*5 m8Xc@{WƅߣA>gZV9\(U,ܔ1N#O.Y g\;j`5"TM8"@W&?1.\xn\Hθn㔗(<)GdEq4 +1i3NLh8 ^YǀoSdLy=.jg.0E0ί@%ZȌ-;5d2;Uk g_3N評10Z8GO840fXgW 4_=k`P%"g!Z1&68Th=JU~eqgtrƙk ePs%dOշZ`a S8?6GLR #s qƅǑ0ge8pp_&{x=Ss:ĎgHY1`KOͳٞ㚅 "=go#*vV^lgFڡ3P88C+Zlth6S8sj +g÷zv/}86}vVj9N:I8;g Dqxt%H|\i#C,BnR$pv % `K@Fɒ`꤃K\ribhuKk^޻˟Bq=Q[&*H!1g?*87=kLG:Ш"h4V+#v OJؕ/m<:{Rٔ?*9i{ƨjaqc7U @ PfP#Me"}M_•-sA]Ss ԰V;L<(2{ iy-US-.օl O;K e[}p1#xHF@ b׫Rwqkˮ:-J~6fl˦b%2j8ŶO?S?KC~6q kv/|F.&1ž#ȅ'90z=ƌԧV!O˽ưLHǧߝ׿XB˱W/˄909wMxࠛL8 SEk 7^Ftע21#xdIWe󌛦3n~.X"dK k{> 3ۆؾrnPAEO:Gauor~O2Obƥ6_Wǥw _{$zk m"pK9hie* &g7g(ݦQ/ed2F4\ }x >N/ETq,.מi w,zZ`q,⬲]5גO6MӱR~V/$ۯ<Ɖ LS8glUthѬ<^ ((c~g QI 5RVXĸ <3 9uh 00r^QP;^ vqfq'9g\qЏßij6}\aZdnW1J}58-u}ѬUt?>\ pzlqwktA[u+07o^繙qH@RPe٥ 3~e -^sa\c[ 8^NVu\#l34-A~ZsKH5.Yl!at.˒n,$i1;ݞ_vyi۳yvx9(H"㴯·Q QtPݍȑ$Yxg!#> ݼ*GKIÿ&t;&8>bᰎ2FH$介pVR1p\UWK:6eǵEZz N Q"Lh54oi&N F\}[zGZ+8AǑ8.oJq;.8cqYL(70bi2D"ԪZyX~׎&0^4^>ʙ\ ^I_7L!:׏K <^ isVcp'ww;Z3Sxx8-_K#pTV+C5CI}q踔hr5;8ep8OHGW֤:yq q|Ƽ2m~,^~ 3OGHr|]9LnqMQ| V*Բ;v/41}>+N pSm&8Xfm 1NrqVq7l2Ѭ6|3 bUBEt-1VXLř:ꥑ|n"5xԏ:t\Bxf]ωQ!Y>ǚFG;9=_g-.[ nQy9 yW&?#긐Eu|hG n- X g2:9̼."7ͱ\LiVc4d$*U7VJ: ǿC%OVL|P-)Rl;a(QbǕ,Wq<1&1.8;`LsҎDk6pVפ2DlXX]Yqi 7Wy_@ǥ Fkd'Ac2UZM;띟9<:pxZ&vI_^6?qzw ybG m*00K珀:Kq"maDdq(r<0.Dǿx.C74y9Zט8Klj޲BVE9P!qq(1'nYejQVpFDžp"uy_1K aGG̍\org C hMX~{!]C=gv~6Dž{Nꢈh vN Lx9~?3MG-wún0qQOV4ڕјYRjU{dhub{NzTW:ou踄e}Hzy>CKhGG¾wC*ni%a6ǁٴwU:oKzIj);`;*1;M6tL!,v YūwXcq\0AP÷."dxx6_?ƠW9=[yP$W7(uwN)LkJu~LV^}{W9K&urmGV*arτb dilii]BV'gokʑf8eҴ4.mׯmG{~[~ 9AAAAAAAAAAA~@vBIbxIENDB`pydantic-pydantic-ba0aa01/docs/img/vs_code_04.png000066400000000000000000000260101517143232300217440ustar00rootroot00000000000000PNG  IHDR,k,PLTE%%&,,-(((..!!+4EEE434$&>%&+%&`ɰ&*P2B$#$%2L.˜,")<]W)'Ƹ8((ƺw7^\Ŕ?;L$%!Ȑz$-G-.B(/asG-,33%%mML-/8z,5LG<=`6N4Qq¡nM9;@F,,ONA9L9G"&,X=g'=l""H! Zi/>3T'+u~t,3i@`)s6[zðGm6>ReXá{b+"jCya*V},FnU\Mbmb+>NN1&Do^ǣ]?ZyYwX7+Lǯ[®Ki-EiK~-7{k8-fM*2O:GWpT3:!/aÆe8U:JҪkS\{~A`[|4_ͯ[}MqhcPm[c^yOMU9a~ozx^Y`AOD@cqEd:ߎ4/k$ni_~>4Z9Vyl!:)-y !(IDATx]Kq/1j,$IMi&+ZhZ:)چVrBҔƍ42!… jó.N>-A\즏Zs{,NlVոߌ=}naj>n•U\S]O=RkZ I̅ے((/* ,ļ)mKQ:tRL/N_ϖk_kdzԲt3R႟@xiMKwՃj&iZ/%d!"+uԹ\Ŗ}X;|ޮܽ^G:]}*?:V>ʖَ9anlu]ߋzI7E%/-p?5JVyƚ.߾>`2[)g~xIEBHeVI)å eMmxjPϜn{ms.P֎*n5CnIǓ]Ț. ǼRryjFwQB4 g \XxrFUYQsr&'JO}zd`[.plv09] LZVZq)W.9;ORw^GSsz}xLZ'ܢx)䏏-]7C`ߖ>StI܈h]GK/Z9-빬Wt dL1JZ[z_xgq7"o9}mzr7g8>S-H$˟D!ח7K:YzRМ?Zߋ[g%|/sJGJWƫ ㎴}P9ι* y*M7UzdyTzbnHgkUwYh2Qzioj.Ur'E+%B]tV|xG:Hs ;]E0b@تl^8&(R&l޼#iВRR.cR+a ׯ ]:n'#U.eT皞-]v2Ju2.JS+z,Ĵһw+մX[yG*dPKH?)ZQ:/RyA[lasHܢ :aֿtgߗMٚx ۩s>ɧGf-YX/gK%,qZ pijc/-|]7k\}*]){l؝߻_o*}G7 UMUKpI=Vp.rR`jZGjDyekP-ȧ :>[,FF< Otu/'ȡVB77*ݖ8q掷n{ș\2yآS9tռv[sXc@2\_>Kr`3n''7pe.}s)59%|TbKXΤsO6%u|恅=\3rHU_LJ4YF*[k,\e~TIiCos4C.EI\fӰH.=jJ\zKݥڑt%/[kt<ӋWpo2o/*Ǭ8cէj4K29r"ΝӸBt~tZ[5M]5;O.bѥ[\|Tp.[?,%/&CwX;y$_r筵thV=Ko2lZą  7K\9D |=dLD rA`ܑWݑ uӚik![rH{U+nޑKSdeN/KI&kShKVtѼ#]P< V>夕h10ċ9yQٗ]{o'ޝ1+[K'^hP]Ʈҕet8lޑƪ#%Q͠Z)j,e43JX e^=](г|Ad񣶍K'8<zj5oԨmOa 1eZזn ={gb=Ҫ1Z8 Zb6u%uqq߷8.( -$`uA""D"q˟~wO_[8ק~7J<\ 銪. qJ4|XsYo#bJ/ȁBKv p JQ(њNqtMO2%|Mktߚgz疳KR*j)Jj%k@v;t "Z]T)Jf%t< hs_K ɭĒ>G5o<Q!]Q lץ>72n)I!]Qt[ Yk"ݕ 1ɱWaGKkW butPHWUᔱ4.)#(g}{WtG_}ޤ2*+R^)-UUT?ӛ7d¦jnb5<hQgRHHsNC^vЄ߱==9]:{#ڢjལYHܕۂ@MFM+J:5:ԪBoN$t5C:!Hwf؇ 7~759nX l*3; q|VrfNɹ҃eՠ{!P#T󓝧LlOhPW7^jo1 伆ZE҃R#@RwH1`lJʐN970qZ|4p&#{W!txqޑq4KF8 ^;JriYVy7IOZ ^ڢ쎮KPқ̓_&p=Lw!]^-C̲kB\fI}eF{]ukJnd;?\۶y ]gf:(]w)O@? ] #Zn TH]D+:cq-K)7*Zz[ʼ # f sZNL+_} Ӕem^x޵́eePmpH`7eIGnTgr %=qխf2̜sFBL`%=kt_Bk0Tlr 3ы3 E L*3F %\*5_QZ3s|'hwztBF@φzUtfִqHIvC!]OZ!8ɹ řs>Ng3!:@5K9m8DJ͂ɒa+B<R7t-jDZ}Ƀm"JʼZ=w1M؁0Ιt(0CDBPv,y08"}' 8\qHInYGOj?H$]gU>(+r0Haܤ.6sTQބ#ҳE:BTnjO)4y4sқ|[ȯE"$SjD.8Dzz ы 7/.4 A#IGr]jYSRңG/8awBa8F ^88M4+(zB|8@#RHg .qHHoHuVj^ؑiUd9YV\ݑpJv^7NCvFme.VU!iNj̚s"nnj#Hgc&Ď[**ЎA$ j{G`6x!_kSd/ʛFϖҸ_ȳ*OI#lzBǁ⧌LW(9G Z"ON3, '%l&xqiSI!PJ5*ViGZ&5B11Q8*i!)!zJih[`ohޏHq # D:MSpVUF,{]{X:Y3&^l=fXGnQx;Ҋ Ivy"+tP 1ZbN:2ɓ> 8>N3Z&X06ۯSo[8*&xs7-mwj/HĨ{?/t ']TP(b"}YoDhKz%b ]pn'3BʬH?뻓2s0We_:Y3-V,q|@:?e3ӡ->b)T9BtrI!=}Vmܺ%% 36H %÷F~P\i㮢$SV@ SbZXH%iURyfȋ,Fc֧AJnI,uRK%%=!B+)˓޶9 D3$F/dƜB0?)LKҪjd oJKrGӌźpLZ2-t@Z8@,|RH@0 -=f:,]?yMGo 4hA b]Vy-hMoJ3@tKUdњɸ+GّtL+fY1 g͘W _jAeK3R8T`k84dI!]t-ŌѠE4ӱp!" ֢#n$_Γ`N\Ry]pi%8"_KKg _NtM u%tkB qIGs@$_Bz5'z9HX!$tV3p3DQD:0z@HY$E%腷(;kwg:L' f{ BK.2%!|xE#.UqNۘhyGc9 CHWmʿ{HE&uDm7%҅/{{Ͳ?H}P2uNyt`abHa N;Ԡ8|x2%eIv@W1bv]~ S( /+})Cގ|enm:ħ' dSp{Q'.qV0Ô| nҡ%& ka[ E&6Jڡ꺸DZKMc8epT3\P`OX^g%o/“f$H;+5haB뮐>/@EL'hE7V"=!tWM5F{lFt0$=]>s&"[Zcŭ'"=)/V@z`C3^^N42x^^)}T\"v%%eB-ݴBֿu#FthM%eip)LlU͎"=ūI7H~pMPFKhZ$g ѐIǑH5f)hͭr ENΤti˺"}C71SnHpl ={rLl|DڞXױ,I1 8鈡GI&LC? ]rKHIf7⤳0E]l}zhow%TQ#| فiR3eJ_&!̤sLA8g/15_aYW BI: dRGcS&;ڂ[G#iI4HϞt^'v КŤcDF= % |;1v4"3fĨt+"ԑxycUoX6Sn:dxJ?ТV醇|GtRy#5IztB.VZӹzѡOYFw.C&=eO26ɒI'jJcF^$@tv.ua*Ii`!M_= gjO oFDdA"}}R );v#Z@%JH? > KsYψV_ZkQ9A"ӚWH_V]Z!A""BJ@ YC5RR<,JACAЃx[B/b!$g6ɮI&ٙq=JuLߙh^_z -?VVſX*4Ŏ{v:_v ;t2]P+B>h麢mAh e@)Pbۦ3>^[zvmdGED"Mt3[7g⏝ 6L~"<M^;*_c|7j Eۥ]qW&T3ggKmrf]@P"z6}-M?Gj?T^g#6#b+%W4lezHdR-q*G9t:Qs:d}{㛞{2}LIrk;2'9<| tӬ"eJ3MC5-dꍘp%LH7}`P_OA2=;ZgVfpdnY_Z QY@? "L4.oomkSʯY }ٛg=$XZD9}6pj2ٗgO):d:e͞htSA3mQ&7-4P+@c[Rwm|gˣbo:^~|x27‰ TcҡًW>o75+hر`t[6cWTsWh.GZ^U6)ڑ"]]C'7-x43MǩypJzk{A) A]H=}dDr1` `zbn6~sL- &-y|#߅Lin/8ҚBStNd@ܼL4yʀ5r%mr޽=yzt:Op8P_\rtzMn-bM3a"w{ܲ G1:i:rM1,BSl0 rakd:3];Ld71{tl/ipKQǯ%2cOcfDmEE}_:Ԗ)&N5Rj)Viطsn.7񢉥>ܛf~9ߓ^PNV2n+MG?1 1t|':hvJ/IiDǗmwާ:3 1[-٥pCPĀ1rtܑa~d3\پx4x.9]wrڱ~iWu8fNv8o^)M{~#PlPР=t9]WކrJS5>/A5:ϓvn:AAK<2f:@?Vz7ӱn9KLaN7xꈙ^=5k]ހmmge|j@qr%ƀy)6\u%C ͞FK^ѭTT<=7WA$9^؊zcpHu|B2gLi/y%rtv"! tHHDQ@"WC$ WWg_PnUGj/RtBEK>N\iq|0R0f)%87ȝ6r_"?I{Gי$;z7>ѳ ;7`^qsIw (D{qBˌ榛/m2y!<<_ 蛅?+'F>hvVMnS30qL&`;95ދUL? *D%%185AH`_Mm'w?'@+ؿ+XG)Lo^#8\KQޏufٸL03)dm(+RnH11s`i qh(Bi`:MW0qchTSf2ә^xa uc4K?n:3S$M{2 pbhj;Qf:J{7W:er +FǑ,QZi]7Xge^A!|kzo2=v|_'~3=Vef龤|{Ӌ+fԛ bFl:ej:7IM9[o%(0Az3wpyz^T߸-WC@z &.t!Em27v!v8g=,r )rZ)ԹyxW)7T7',1Zy M Wc {t{,*:Ǯ( Hk)ݙf,Hk-] B1*0RwW 6ya}I@ 8f -|p^.q*5wkn]Fuldzg zkeR0!#=-]Fn:]e԰#meTT#X¿0˜SSvM%Xl&,^\9p=NʺIiT6qUzr)n]FuܻlL7 W-a]M*{$se>AGwb?_J$ `'Z?-F#ADHw#';Rm{U,E#Bk~O݋ 3ܴѐ'B'Y#;GAbR#G!?}o?]pZGtۜ޶xO'>F?F"!/nSK&z8:葟ogiwZYYY{L<,,pKw5,,J -~~~+>R&8ZE,-zE'SƟ9\lmmh]9f:..?h.5_:~ NAAA?=>989pe<444+,G'')3RssrDDE}L1_3-rغUUUT-.L1yzzkPNAqkJ8=HsB菫O,-ꈈ``_H?7Q3.̞GmQSvww0Eu-,>b0U) Iz[[[[LlB$jZɌ!<U%Fyӝ7VBxuǘɌxcMFF5^zMBpd B")@TER#1 FbPIA"Ub>0;T M<F##Jȳo!JDa_/^ < sh/]osx,#u029% e+3B@*ȤCtCZ KaPoCPvChn1]{ #MQ%I*qHߓ`/&bI#PC )xɱ)EH "l7j/!h3n$t^ bh5Ev^3kEKPaEM*1B0βwM8i#{3 ~rk]h7gXcpM}h<9;y #1!Z%:8&c,GSN`1&i"q#D,ƨ¨˄gg"F\5PyjmDAec#Ĉkjk+ƌ 9}iDcLM551ZR3:ڌ%`tA1r3c_6vnfeb~l97Y(Fz}[㉿1'MP%q14~ǘSc4Ř N$0Xu)c ctF;ԳzW~b H@%H4'?F&3F3 %1@E mCp\uV;_e 7qJNMF88n-1-<;P/'K!K15R-&!vŠu*SuQP:89 ^qTo~pO;$ 1c$*HT #QAct@q Wz38~hI1 ]|W#`O#oXEq'o޻^m»sfGDN]FeIU1k}b{j|#夸y(!0vfy x7s`*9q T&d7`IZz{.0b<}cζ7^8HrHǗ1![AhJ z?jAؖ0і!JjQSJQ!c5w)|Z73ڱw D6YhjTUM("tTg1^dpNyZ6CĘOmbcV/c=O=Sk2j.~֧=.ڷcV)л%_\eۂ։oߝX˯Fcj!1깚 V a4}Kd6+_/kxsGŖ/;vp>gcDg(*5-cE-5 LaI+HBѴ1 U :bAu+L ʤD|cMYH9ΆKv /}fwb+8rSWQb" |[NT*ぃJvTD6Եe$ʱ[RbDHR6+w Kc|4U Zoķ`{ """"""""""""""" ?$_""""""""""""""""""""""""V"*:'JQ1F`D߲wAQUa'fvfGQ"뚀,DB,l,2XB`3HQ4AԡȔ@&# L蘊S9=vG7ɽ{sG(#xeD܃(7&|Nv~)ʈ3 $_ c*8d}MFp".R;0 2Of-[0> 0fdeD܁/cP;iWd[R=- qi>m_6h=8np;d F6F wxzX82"4Dƹ]q931=c+p[ҴHx 2f+mܾQ>|ШTpTM"2"8=6'Zƌ^^^-`Ss0E˸d=-Kqi\r0zɜ" k[QF-Ƣ=RRLF&[}4 H ,;LOrsN^Ư ʈ'"#\KS q c#lg&}"lr_kJiVi*~ Mkݐyjs6E߹l@coTp0vd,Pd0"cᰑ3V.{xKq`(# 2c;eTߺMfM6fRO٣ X>UʀF-˸=3$ٮ&vDfvAėϮohE׾/ .@FFkN\̻9wR՗)n\PסL_r!88)m5A/UÈSV'G2)EZ?[$dG+G@e䤖pQ`<֡)H57MhQ$_F[$!#Ӣ޺ *hc8]Q.^eSX7Pe 4rwNHyb9g2œp$I_#; q %+JZLC'(Jd2lR>嘢}EoYc$KT#^[wz BKl9YrPHxyNZ!%(k"T/><5oHLFO(VH^PK.vk-#$_jSb2{VJ6֥<]%twuԼ$I0jY%]w]j?.U}s}xSdi$+E{#N|@b^pAr񣒽etQ\S%om 1Js}=i uۢ-ij_[1!^3HDMot1/^T^FvwBj_4.|`cߛ!:˕.X[p яPf3ߖ]ET•%TUYԾqY ZLS]Qe1x3%l`E|Q쯎JOe qo:g'#;6(nyMjg%ɨ4B,XTk:zTR߄ G]p誸_E45T_}6,2B6*cQZ_IXBr92ƏW׬큄ݒ^P}NGW;gͿ2M#c/5yΕ%;*QFW5eKɼä2IT K&ш\`MH-Z`##$uO4HE3z?nj5#I#FKؘqm%D=я2l"cmTƫ%ˢqnյC] ]GbÊ d+ioϖTuPM2d&uR7 cGiD4EHRM'OAƳj5UAPs%5{6j$lzΰƓSTIEe]ru;RbDZ#4HAw6p\LiW8NjbeD܊ѐ۲Q74ղ 7-MEцUFʸ4ÆAn{JƢ@VM.Uxd\ 4!چDmYFkdd1F━0u7g*Ke7 qfCpF-;2`ޓ2fʘӡ2Txxgxv^wsBJoJ~9]\D"S%=lޜ73ϦZed1 lɸmdUr/'ܹQƬ8f%^->7ql#.ru@ƙ&|ns-\;f%Nl#cl _EN!c2:i-XѶxxk2*}!˘?1\e,xo*@̬-ް%Fm^o呙ryCJ!FJ}Z6n4LhY+/c{ F)} ra" !R.ϋgijp*L~FeϮL RociM\iȓM\.n/КJ ;%G1a9Hrr=D.IP'=ޛ2 m [O$7Ze+R( fLF;[1`e~YIR_C#zuR~XFсQ*SHJk/+T22_[l*DhHF;fK{_Yܚo8_6Zn4վΜdm23e4Ր)o)&|k QXz/ukڜGFJMʳji̴he5I>u\=UnQd~hh T2zkgW 2z4B)3Gb[6W :fX5Ri##jFHkYoI#щЗy䧥*ci|M@\\!n-(,V:Oz#Yb%Ͽ"(WFxo&\:.($m '26:iM՝뱑294fuܨ>6LFΦ[B`״ 0~lڍ6i*gdd1[ْm `VJ- exCT͐Y%@9CG¤6Ǐ[x.m*Bĝe,~\+2f%ч3J=<#aHd4pqS,GeWMeė2"@D "KF0(#Aʈ eD2"@@D "PF(#Aʈ eD2"@@D "PF`S[S2B!#D2BğP7u |Ť,P~IENDB`pydantic-pydantic-ba0aa01/docs/img/vs_code_06.png000066400000000000000000000313121517143232300217470ustar00rootroot00000000000000PNG  IHDRPI_=PLTE%%&,,-CCC..!445!+4̉.%&&7J%%,$$4%&sc'%%:`ɯ',CN/(/](+P7"#C@&'I&&*/64UU)'RRRe8-E, [ġ(?n*3iâorF.\Ŕ);]"%Mm7*i#a\:,nd]v= ĩvPM@ƪ}JNDpO~j]*&OjG.*19&ǐzi=:>Hr7[6=gnbH.ȸT3Pp{D,x7L˧ƾ:_Ʒ',v9F"12Di"#WǿĿ/Eh{S@óP4'CsQĮ,=Q9ANL?Zz?09uu=10/aJsI[llH0Hcqu;jeѹT^?fCUVAWʸOĤ`LP.[(!_l]v[i9,ZR̕bYl0E1NO,͜\ZB'2D1QXLme}F|a|M]H$V/=m\Zj LK4E|/tCn@ڶmUO)˄ .Ԡ1TjLF}P0agyg^{]]{޺Ѽ](OcRƼ6,aA(WMu䒋6ghPP㡢F =!ߊO ie۾Ȅjm?}KbHAsW?N5pc hv nTAȟsWDUq j27GQ3;wJnV#DO nW/+ܻ7`''6AF} Kg "ԚK[F{zgV"؞_CI 2wenYG(9 !Rg"֊/-9.2<|a'%I~]5E(.q t)6A5I Q']U TJNv֭կߡAsW7k ȈB(/:ꄲBhxu2\d~y~>i'5B]*԰7` .?;ބ&pܕI:= uVB7 %IIP7E6G]P 'aB.*! NWPۮ ޘBhF>w<$^?dI P,֚.Bw\Jra9M&,VP63HWҽjm?9D"C#_8.])8.Ù1dᅆ)JH,HӢJxnu!Hzqr85BOLM=zz8BBc?"g*KFlsl&|,6RPe36gkZ؜ (i9"'p6h[l^c YgpXN'oP(SS}P{L09XX(WP±٨ tJu$Bqֱ 0 ឆEΫyqx R5DUU>| f{]BPXSV92+?yvw>4_!IP< ('šwִOHq__ܙ)V3sQ)ܔ%3#hX<+y&sDgZqQ,dD_o77"@gg0Y-c.|t*{R/~BWa2j0C,Vq ;gYKG GS3"%q5HZW_:v`cxV!P}<,sZS?|>B̂#r_jҬkV9`uAˎ=TڌV17u>P|T0ζATZ?H~a (^I@]3C:J']O@ jG*pu(Fw`N)N"Jy;W'N8 ngJx9O|9Hq jd9ľ)Tsr|@u]OcJp&084&1БJ iC"At Nx8#吭0}By܂5#b]ٕyWսq`@ᯀ%>hu,P)5hR+__ yˡheKf0t3pG@9Fl!zCήtδ] x &P0.{֔8j&xBP:QPE+%LyxQeQ||q%f"0e@t䓇cf\z+l<}`~=zg@:lS y:Bndf*0琟ĭ4?8xC afƄANxi.\_?Q~cc`.R^>vRkXS78_k)15tz5ޖ|exC<9sN陃? fC 1Pus"(+p% iCcP O-M%S(7ܯQ -j_@aK"yH^+ck`KR-kz @7YN~u FW\ >`Ѥ{H)m`Z\|msdޖCb6+\;6WVD"-+j$8|ۼR([}!sv5V< Z涼̅kL"jcb[tݔ m@8[E|לa@L1[p-+Mz| 5!q@ݧH/@maOX"[jt|+m( )(bTnvsZu*Po Po戴"DN9vjP2l7NȶJUP@ !Lq6;8ɢPEg-q0TT(#3 B0+VPwBL ( l4퇒CjV{?)P𣈔v8C'qCEXx}5koP,@ITEX|p;Y:t6(AG"{Q4 ;'(MJQ 3hɷmEkP )٪D9L}Zd}:f6To))NPI'U-L6|Z9iVZonx`l,+q(*R^Gnko(i)'Pyt˫yK6oym)U`^b(~w1qTan "˭ FZŲi㕢% ޕTh"kj5jbjC4jieM|9svv٩pޤ,Μ9̷2%⎤ Oi©m% &Cjj2?[o}aNT욖k&4XԊY0cP-Y7lr^P N 54ߏ-o7QgwflUp6C!"iR{PbV{ePL. یU f(qU.hJRDp-pt[r_|| <-#V ,/zUQdu XI'@3%ЬE,U-uCE %W+F srK[FT1n#M:V( kȀy[4Pm^8?s' (7uM% JXP-foƝс"i $|Rg|e6D-U*P,`UGVy\ XIO}WU T>v5)b΁Vn 4{#':7˫@>ᖌ`͓' PZGoK@увgHF>t}OdIOiޝC5iu`(ڐ $3O 7&$PǮ͙[9P-foE/YL| -AҖՋŗ X7G u_ }W@ρx<\NPJ.7ej,7f!fDGl/H\sx[L_*@Iu^y-'1}M$%ր E?ۀ=Ou?{4Zi sF4=I(x&RqVl%yޏbFdWϊG(FРux{<8ss-4'-Uco@[)@*J5^9JKa9Ju-JXڄg^T^=oǦĥJM@9ʫ@%*.[^_c?\J?_j[&uY'DP[=k JQ9OJP NV@JzS5P^K@Q - ēK@|e2L-)qEs=GyO΁*n1skѺZhw_5 |JPt쀒.p=9ꔊC0cO춃Mǻ:#}T7J0sK)q`xWO@i&~O EMPyt{'Wis P_khiԍ;|Y2%PKm5FU(#^e)E]g@ x¦LQj.j/w Zn%]TesD{ѬN1ogVELKnA9TP&^UQ)$ tSvI(+<~:@I%T=1{5 C1P.rJk@U |(n!j|G *NlfLc76PW*g3@UbR_vڿn]V x{QρR ȣ0̽%*t׾<S@+>v 3,Y3xY#p:Ϊ]&Jq^@E(R:_qo3vo( 3`E>́'ho3 ޫ֮qkI@ɢKek* 5ZnɵjVE̤ C^ʝC+.x( /SzY(: njo~@ *6L>yysQ%[8Cj7Vzz_wj[V @^jR6_@) +#{} 9P֭ex`,g;J7vđ{\Z${Ej)w^~׋@6yaM) ?mƹd?d#顲pß5RP*K6ݗv?,jW慾/.Tټg9TߝF @(#Pnhݍc&Vzh CbDƀ~qu% SZ wn*|d9P 1A0T=ɬnck PY_ϛ7/3bjl@$V^. %y -/*q/@8+=Z}h4PQq&%J`IBx6AJ*y16K`׼`}W*/k/0Yv<3񕵙P0 - gwBSБre)bs$J*V OnT&~WB>Yb TR}`*`r+m"B;Ɲ 33yykŲ;0 SCgQB(^^v[RG؜ǃFP`f|@.4o,Z,7F`TL#8(|0xa@iz 납 uqέ 6moBJJ[61v)&X8'ni7rԚ5/qL<0bP e ٰaScSϗAd#!rm_i.3`傋AL()řN&@(7rPU(TP6oz I/ݕ3ҼP ə7ES_ZI`ۖ@*}wO /n D([[Bdi3\'T꼄FP $b".sƛx$$|qrPE:c4B0l6gs0]&*ޅrᅦy yŵvNPLJ/oMP gg^(cۙlV( WUnPO&+rPS3^-º 7)TLGQT:; U{=1>@(<Wm!R6$C \6_dܽ䵾"W>ɛ bXlPAX[5kvxqy mypFޛ),f=WA#Nѣaj IedgJ?G( VÃL$~H(xI ʼnJ?H(B7$T@B# EPF F1RA#Faah Jĉ=l3=mʴgoa~^>V3`ޭa5?F@_0hPX:4K}E]셁ɝr,'n+W[a&lv{clnس߄ZQ[T}n8;KPJ>  p7E08Q7? }0P1E(B.MpGe`B7WwZWDJPF Fkl'oW{&mO~?.GVـC %|胲KĄ/<\N&|eVdaaٮǿ:ِsH8C~B{V(pD&dWvop؏irv0p>:z ۣD KeGj*.۵~oےشr%^O#b4)S\ڭ D z*MqEY 4 U~YP[ꞟ{V&W,B PSش; Z@}1>1NjhËLI{v'lYV"36ԟ+qbv0 -HLlAdW%\:PU=5zBݢĢPvBA8hy^z t%"P(^!p !=k|@B1rh*%6RFTM(1Fq%R+jғx$jqZMq9V(0v -rBM,-bo_ {/L%T(:FuU(5S53SqE(mʧ uJ!*z`ʧzhXiCJMXL҅"S1f{[|ЁhS>#T r?C]c*#P(-COJ%rvp M,rQa(Jູy̘aaU"(51M.%Q~E(a1~7wWs€S* LX~rz5}$QTxyE ,>ToJ1ZlkբD 9Wo=O5jƲ&J~[a$BAw"|w*T@vҺvcm=W[pl&}>`S@BQ6WYX6~EolViC 8vHah\Amry XŽ@@ eG1WM{j+wq.tK*` Uf9DyχZ7DgvBb o۷hYs&?z$F# e86\pEL_9H|w̄sJ |_E0f<^q}##FFPgڥ#EC1 Aő#EC1 ,|EBE(0$APaL9Az(B EƄ" E( ˜PAC1E$A s(0&"cBB}EƄ"APaLH(=;@5*HvPd@P$(x59 IENDB`pydantic-pydantic-ba0aa01/docs/img/vs_code_07.png000066400000000000000000000331241517143232300217530ustar00rootroot00000000000000PNG  IHDR?s'GOPLTE%%&,,-..!!+4(((EEE434$$+%&,/5`ɯ&7JmML$%,5&&sc'räq2NNA&%=K.[š*"&-`G;@e9$(C?#!ǧ\R0,%*R)9`m+D~;/G](;lDq|7]sE->6.G(.CXRK9E"}fV^*(Iĵ(+t(2QIr6ESc[:(3QqKZrm8)\qtG+&M",:i#W)&bb-%C}K||jyOeoL]œ4Rɑ|~<-J$&-: -3^?ua3KIk7L/a.Fm5=Gһ X5XQǴ?bzQO]qU!HeM*Ⱦ<:=E.1LSrYD;\5hE1=g0; SZ{sP~?[|LG)>Rǿvt]C4rwiXY+W}}nTɹQAuQ7Kfyk9e]L9op­nBc03=punG1ho4Vf9S3mDv騹zѪW7ZFmPX:@zk:H8*=\"īw€_jbY?gD_QZSZLdM?f66O\l`zJd;ln\pM_i=^כPsnoEmd֞\Ztp`]WiFVCX_WF2rV^Q{kqmiZ\ه3bHv;ipYl9vl%&n?Nz+Ck8IϥezlӮ(J*R~5D*E9$ZҪ)ddZxḞ!"7]q$oST ٲF2Q꠾9,Ӓ+[phHQ$mj*AEɤ~3M/$H$>"s%,^ͿͤnI?#ŋG%Sڦ27d#\V` 3]eWWE?Ҭ؁~xLk+ż|q6oN^wk)j DR{T^We#c~n?bE1 9'WO,z5(qY(D\YE?>޹W?6-Z:zD{}UţR-EXB?X xIoR4 y]^H^kgܮ4BG ֏{j(?msbIdk~[?j{ň^h?[e?c45;$gD;?~q7\8*1>uT\_ obZ^l?eSSD$|~[ڹa4akc~p|&~`IN+~r r浾#+|?* ۙZoZlQ#ד?d.7~1?'ku*x:R/u"m~k1\JYϯk}i,_LEQkAQBVBG_ǵuv=?j*EmJz\^O>/R\8\b~VGiVRB?Ͼgo巿nC?G~@( W"k| |ͮ]^߁@pw(X__Ow; m\ VgPCoZtM<5y%`wgs8LP=βo'=OFna#~@@?P N5;v T=^\Q[os3" I+w)]5О, 5`s*ܺxE짟 Χ315E܏jm;Q>,@hseC훕L^95 57\w3Ɖ9v+J'ޞujx֦Fr#h1u}N#r 4`SBDԺd b+Y4~NUx]i;yH& LGP[Kt|~8*R(|FvяjꢟN3VP-fq?ѱD[.cs'8Q-OI|g+N΋H04OeFT8P-Ή~D~iU! [jXƹnComGq'*1Ci?79~(I?Ry?߬s?S]f~ / qjb?9o»*?~MQۥ!uk-oU4~8;0{G?(Usfe^ںW:elGl*V CT_[/#G3$MY?c݁Ty;V$HʥP~+~,CKgXe 7IG\r~cQR~8[~3xUΉ5]"v֛vc!iH jYծ{58RZj[YS۸WVmu@jEL(/-}b~]֏)-سe~k˜]FDd+06_2eNB?!B5 bUWq!T<5. m(\,:GAF-UD= œD:ߐ:ӚqVj{:/~zپiAȈ/7ƕϾ`ۆ1h,J}U%ayD( 6+ێPӐs]uuBA9~^iӪJimXόoF~h$ۥ9↜y%Cv8ן ɍ-:DOrjW]~@[N"\0bB~ΘYG_ (86tǦ( .=(g /ԩ?y% 2)IK#rO} &sAMpxAH>jF?7T' s~Ӆ,=^Zԏ50s^1@P}s~M?p~~p!'O=rxpOSȿR*0򇒹^Z?pmaܒ*O޻캈j85M9k;כjŬ?;w79TEz#8mAؕGL\ɉSqmG?®|?%TCq?uB?xNo'/ǵsOMKf2?XB9k;)h3q{~qآX^z6k[ cӐɉq1/+_~~]yZc#eM*?"# v?bM6UC?J+gL՚lf?߶tZM#J~v~.gli~'_oOH%~DmOۮ{eRqs/k~CzƝZ~uZ~X[]ĊA7u~ώ33c|yā}ͼO;6vZUsZґzɎ*D$>޿meR-_~gT*LྟmC?lߤo{޿m߾Zikd v~x~P>@i2ǯKW/AEFܒAت.!;RXºɞ_[vv:s15̨qvOa~8VϿ@?@@?]lKa?e;EUҳfش c b.:/553Q ٕpAYԕ16 MzA4D…xx+Niu`~n=S.g K72)1SQw@5Ϭ^u*%KQu45)^9w/@1tq\??oMMn~ZTj3O& (eX~CUUf'Q^^k.u,$Қfm?sؓ*gPqt*B1WrT3Uv9׭~>%=9w**/D1lOF1`Hy.,%Zd‹2I'st8Eg3Yo#Ƴ3~fY:L}h\nxi ybqrVLj* !厚~僛XHR6i @>vTEF0$ݏše?7eԇvzGcg*|AZxk~ޠ(Rx)Sq(Jq?=xک:B3q9]\yG"vnʜr|vH']?dm- @^? wCҌjJS%& ~wͨ]ucfF5L}(3>N}RN? ~te  ҖrMb֢#`^?T3yh~Z5_Bb6Q1 `HJ&kq?UJWԖ[6anuu{~8ݼrEKX$mergEp3Z?f%7Й?h'*#uY(THWOjl"qmړ ߟ7*c؍U/?2?Mr1G_Lm֏m޾h,2"}U0&5v9p&92 *Dd~ o`2hnL?[OՊs|dqC@1ݏN?[ls d o;؄12e"nse==ݾ3E(aݾK4j2H|g#1>HEa0 Dۗ3Xv? qPDmAw|cڑ~P43+Nǔ~\P4 ·fkt~6=6臅_M|T<+i^ͻ>nk nL?_KmzR!޿fUlǗTg~ߺ=t(2 ~ @?&~ CO?U^zDYjPɰہJa~׏v\#5dhKʹIU~ w.~·C=e^lHn:y`{v'sjn?RkΧiwDP;5O fbSX=sn{ɵ{?򣓚D?g% Gk ?B;gDqֈn-TFlՂiTEEDPI-B^JV/QiD *"⥥PPATP~sO=}~*边chiM'~Ln9us#m y$?4?Zxp͏LϾ9Gf~4?Z g㾟2E!~RT`P#iDNo͏O`~61OGKE/[Y>5?UOaYpF5Xf!d|g7~х'uc'ٻGߜpjxW޲UuJ͡yns10k<%S}b@m*G,aϥaO/t4O9?=dC~pnLc҇LNkq$n>hϦHK}k[}q0l8bBQ|]$-u&)a鬱Z$jOF X}nL{8*CQ97Ǔ1%$*W* ?&7-ftOrqS^7Lrx"ؠim;kJWW -OzQ2f'?*Ou`SC?遪-u5.%s|kԷ6"8[4߷y RނRn;nygbVSx`]je(n.Hun*;u4qw}vD_>{:nWl,߸c4n⦼nLc~Y1v- sm6CרssWc߭CS>?o 9Y5쟻@ z5^Ή@@R/ 8p"x%?tz$An:)U`{ivxT~AuUD_<41YAaiB4g,-OL k!۔1ךuXs|~8q[ C{58P< Ry|"ग+K#M:\q2)`NeU}e "-%?- 8撎ݍb*?r&ĭiZq= EfZ |~;2ѐ)ǓOh<ƅ_ٗ;n+O .~ꛇ`JoTjx!›x~D6T~r ^: cr:a3kA2'/YhM5o~:&ng?\-OF]Vʪp_< b xP1X-V!CZ'ۨ~mO9^04?STTP5NEʽ).όR}st~yZdmhM?Y<[trdx߫uD ?!5q4t~*\Z͏VIh~f4?ZZ͏V \~mߥ+7TSSYT*uF-9l2t/~y{~FRݗxӸyFd Hԫ֜muP?3 |&g Wui+#ma5P懃8oS8QD_do4~:k4yaaV~@zqS^pG+̏C gB֎$M!~Bλ㪵Mg?Dy~xj׬PIa_YEog k*:vʜ'[ FdZ!~hihNP231t5\Q&}HJ,C+?<5kVf:bu{f~;B f~ƈp{;DW?W8?äS+_U.pqq~8?\y*#q~@t[N"I6Q?$fW媌c7e*׸#:ʑOH!I Kv6\}@,^P.خ8 U]+q~r~6h,8~lkO׮Ľޚ&oM46T^|M+iCnF:l-)gъ A .mj+hċ C \]@ &C11ʆp‘Vp&pT{@ReWd \|GR;00p =r y1XaNZ]L;?3^_W~.A ~)5QaɸܢD~Ԧok.UzB-3"._Ww49FBF EbۃaPɦZ# # ]ɕC<=#~RGa}dU?huqUօU##~P6Lmbiep0&4 zd\ũ o a GHiadC+L¯Cg=!4XOjKHƨ&cR2A+TX\؟|Vd_a i h-']sXyaW'?tEyItRaOg$袛a(0~@I?6clDC,穯fP Ov(lFM1C'" rD33r'EX^:\m @Tkcs4T^{Qwx2v^G}?ֈKd€*ꉟThbɕկb hBb]szh`v'U?۟up9ȝQA0[2PXUV-lA e^|v|5$zN'~tIO@:A~ (~Vi PZ3V/Gkj4Ca@\?0+}sO-`oKk``Q5_ZXT.|N1?9PaV˂5 =@ipdz8Q5 9p),\0jV矲g2U0 H ~ Zڱd:sb%cXrv޽C19jJϬO }56^d'+?c@P~"JH׎;:)?,mv2#~fg_h?˘im2U.3G0NW[fo+iWttUr'Y? G~0a0kP PIrׯ_&L|^U*~~-DGN&cuO{lx_bdXm_͕M:]&O1JTsqD.OM{p8?\\cj,Zs*^=źZyf]Tau:n3-k sڛ^=K4jGL|0s3-/9bB؊a{\UA7piwFP6~g B$?3a=}Y5455ͽ\?犀G&I@ ךvOֿj);ji֑O$zjE9?U?B-en^Q s=dc[8.77GnJbymG AĻQYGl"`ABRU,Ax AJ!{UoE_O%'[Nk_O!G~9M7b9L:-2_(!QhCG]akG_\O&m~wܟE#M-sXLKɟ Hm2&^~՟Űy6Nj?fb)Z%i6Q7 r)0?+ڋTw(zAA9FKҥvS/ 3eĬ~^S5&_RJ0qc$S*Q +V6N>os6'(Y5|@<}T3*UL{MB~?)Ÿ_a % S?G#0G#ŸZ,Cqm9xt7|Nlr Gy<[e%x{#&՚ХlZU7(ׄc}߆W:\m="Kq~B k΄RY[m&y/$IN9nnTޚ7WwU}ϋaͫwԭgx l2)]^}voᎎ"_bp{Ф$ M 9h٪#(U!ϥJ'18Q0OE"%@7x !ڝ-Ib Ӵ_ u}v<أ?+S OˈCC1ߵp,,W_f kYzL\jsA-3ӏ91ȓAߜI s"~JtBy~u"Gr=_{ ?')1䏪=>1IIUo[O#T>(9ql̈> 'j1IȎce;d8o%gʹ?3-00Թ8ǚM$#Fr2o;ڿ m豩ݺJ~8qmsq_t.l$?!gCbonR,~6?[`b9*ˆA Co<<wf^'1Z+l)Gn?D594ϔ./=^??4@2uoζP|]? .(.&P9:mǠ+\o=zJ{jz%1AyۀԈ4~ON䏽*rk( ՞Sэ t +?!TBRU?~=/Jh~ ˩`H#.SZw:Fެ[eO&ƴ?/87QNphLqA+d^2_egB~ŷv+k~Mɱhxs-9V!U ~~O2[?Zi88<$՟ɲ8<@ ٳc bd ׇ؀ulh`Q )blt"g3I@:p=t~vK9I@CXl4D>,7"@Qzb㸅~*?PFs8;+bQTIENDB`pydantic-pydantic-ba0aa01/docs/img/vs_code_08.png000066400000000000000000000255561517143232300217660ustar00rootroot00000000000000PNG  IHDR ly+PLTE%%&,,-..!EEE445!*4%%,+%&$%%&@5$%`ɯ<)4W6Zm7*,/;- Alȿɻ$'T[ġI$%'.b+Bn@3+5IONB]H;9__6Q2\,7/F+)@&'*,E{8K^/A^ʹqPaz';c?!\Õ,2m&(MN1&+6-]tF!!]0PrOåsU'%M/8H']*&[Q8//:lFsYs{cG5=BLɶk+ȞN5[%+wj6TASgBa+ƭ"G}E.6;)OB`yKhu_8W6,He-%߷̰Ķg\GJ2jk*@zi Gsh2ʔ;R5z!M&T%1}pA-1ZaX4޼nLI![IgH+I 0c7X.~tm'hf&``zmg֠^|cPqkƅYEBkjvVRqq%=I$z='IV?9 Ņ5[Gfk59oU;+@x$4$Jͮs ]4Z%X%Vw/71 FDQq\XN \bѭzH\9+"WO"S@)ɱZ-ΛX-r9!bJ})Vs Bh.\oJύ̌YV&PL;+UN5r 5" h'-Fq[W9./hɱ| ;yA@$ Fl:{UCv^(SSvё]gxgjݧ6ZDc0N~ V _Hd:{q$՜ FV e'`cd5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\ax=ܿxbrKo&{|58I-Yζ?jGT%I6%R y3U\Pbq VkRKuU+sVq8[宭SSmmg*BE`}̓'E`'uSUV;dKIO0Zc4#\qW$DpzB;I^@ ]N ӣh!9ye/n=yVftor dT;pħ06*0.Q//F-]  V;޾=eu"-F*(5Zq nKaVi[ʮ%ffgm U~6!J][cʩ[ҡk{0IqˮƵY}+n@()zm}iWw ^y!cf[G̀FcبymąMoI rH pk@E=1Vg7fNF܅g[{1RQ vvS8n&rSS1 @_,`6ZP}Uy9{'?0`;_1.A;ŗٛh=VW?0q [m5C1j` ӭ}9i/1[3.]Mq)^|!Yv r\쥸s]I j{㛰;]͕7HdnG`b76% ?ˋPۆ&NqL  @; (>j$} hf~⮆ǧ"zV[=A ~_?(*(6 O 8('" jHdcj g*'A2LBel&"eXM3Τ$SSa}o}r޾އ/ngr©߮1=ppJ4C O5y;g)wNVw5x >_A{!xA}P~gx"W#H3̳1A")X}ǡ;6$ҙ@.G i3V0h@jVcY q68sj6˭Iy'kVk m DꕥiLnd"DR<EPA\"|Fkf OHXC t̓5'N:rЭf_MyUVnܺLI"K`{=z)$Sʬ잦{$PS.h,aNݳW76G Z=6:h5ZmCYV V6h X@5l5V'?\Nȴ[ R?ZN.&D(KG[|.+W:b$9c9$RҔHV*Y_KdE|㣭\~=޳=Z/EM]SdKVR:Z?VoT[r}PZ!7U[]}\:GJjX$4ZVRj9,5DZq`,G*RhYya$WYZPqP)ǚ[҈V'6NV{~[Px'Y-w7M~;}L5T*3s|F2a"_t|_+ͫYr[S6udI7ERe lx_Œbqju9wRAQfl5[/j|.nu}njqb|WUAI¤wDvN9lʭ9[ ̡,XhDЖF~I}vz"0V碘ceKz{Eĵ?BYm^`"[3qvn^VÑ 6j7մZHn5 N3Ot8j(r¯Y'Vsf:hV X94.2a kduKmʇin V jaM ʱaF聗+3jeRCTQ հD<)P3wTzGnۜ&TlV2n5{61I2uR qu9Pj>(V'k!y6eަ=זJTE=c }jd`p1->nω Ѣ>Z*:{|$Vɯ5G=67ں<':iv֧pbQZ͙wa,[Nkd |$3{?B<-M F[X^0ٳ"p3{ߩjf͡Xs$֤i̱>yf:i5)gn>͕gZ`f=+pD^)-^<&L겔|iuF[,Clz&9TWѷY=,QVSfՈhAZVم(Eq|q6O"h(d2胂FM*,(u>Hz؇Pb !z襢36cK6v/s=ssjjxnDqS/2Y>rU$+˚dYͦS̞u}<ƾ/kθnL5%'}iOKɲ\* j 0XWfo})akMEu IX$lPS.-P=P&eL:ĨuTμbj3[Т kDcj5Þƨvۙ˨snc 79/%=xFB@H.Ld@|Dblؽl)]TlPO%?.";mT^IR҃~#5lι}]uS_.Q*B9ATCF+ $UBBjkHfpn.l%$MX1CM%_WO5yl#Zդj J~^-whU#{pL< /*jw .tF3|SIH#Ѣ_ $Dz r)-hhFSjc>hq@Vo6}p=p,Vn 3dpfrJTc3j Cx>qӄM"|x) | 3[ON'cz$i*`v ?D5tptGFw7g 6É\a'`uu1?K*t:3T!2#IUP-0QM30MuCTrn/\JMթf ܧf?Hi Ջ&x\)jGU)|.sש‹XӢ=Qp FN6ݍ@~r60~X+B&%o,~GRKטa {{ugRrR"ZɗaMCyϥ!Tϑ&Z{kX8wg(TVw" ۓqaTS yZE#6I T7PbE8Щ&3TD5ՒF* p "bo$T3A6QUT %lrLT J5[j(.Te0JR3A+դȨ>o@ s|*HY" .`յRW ?ddQ*Y$6 R-(f^^0ӢhcypeBgn!Xvv2qfi1nP͠0Xd/IʼnjЩ&3cv(D5J/rJ=wigy7QbљL诞fz˞]L=={E.=!w?3?@6Rl(GT/Pt A8pcjJ})7/*R:,,%k,Vjh<@&"|:8, =#hD Zj2$ U )DH>*0_,sRw"o`F^y>ռU֍Z[nm+c?HU1oYKP݉FV)Zpd ybǖw'7]=ϸmKCFbO9SKPB@ʅ˯t]1{}. zj P =b\{BG>^ ڥn{*gX u&+RTs\F8gL)TS;QTC-T_dǓeQ^Vh i)wɤC<\%HXb!|C7J{S$csahe;ۤNݝ1?o;q'SD;浈6@(LRنj{Յs(u.fiA$OYa*ױޕjނ<ƬTHojlQU+V0^HĦ9i<ŧ $r!D|N۩N;7KtosWcC^=4&2.73>/اťӢ/, !]Uzx?ۑ\­Ó~(4L^\u'{, |j- 2ydڅ\hEh$!kypBDZU ;eCZ.*z-G4Wu'vp@A'!BS5),KUfVGjzGjzGjz#: ?okfے#QIENDB`pydantic-pydantic-ba0aa01/docs/index.md000066400000000000000000000235531517143232300201770ustar00rootroot00000000000000# Pydantic Validation [![CI](https://img.shields.io/github/actions/workflow/status/pydantic/pydantic/ci.yml?branch=main&logo=github&label=CI)](https://github.com/pydantic/pydantic/actions?query=event%3Apush+branch%3Amain+workflow%3ACI) [![Coverage](https://coverage-badge.samuelcolvin.workers.dev/pydantic/pydantic.svg)](https://github.com/pydantic/pydantic/actions?query=event%3Apush+branch%3Amain+workflow%3ACI)
[![pypi](https://img.shields.io/pypi/v/pydantic.svg)](https://pypi.python.org/pypi/pydantic) [![CondaForge](https://img.shields.io/conda/v/conda-forge/pydantic.svg)](https://anaconda.org/conda-forge/pydantic) [![downloads](https://static.pepy.tech/badge/pydantic/month)](https://pepy.tech/project/pydantic)
[![license](https://img.shields.io/github/license/pydantic/pydantic.svg)](https://github.com/pydantic/pydantic/blob/main/LICENSE) [![llms.txt](https://img.shields.io/badge/llms.txt-green)](https://docs.pydantic.dev/latest/llms.txt) {{ version }}. Pydantic is the most widely used data validation library for Python. Fast and extensible, Pydantic plays nicely with your linters/IDE/brain. Define how data should be in pure, canonical Python 3.9+; validate it with Pydantic. !!! logfire "Monitor Pydantic with Pydantic Logfire :fire:" **[Pydantic Logfire](https://pydantic.dev/logfire)** is a production-grade observability platform for AI and general applications. See LLM interactions, agent behavior, API requests, and database queries in one unified trace. With SDKs for Python, JavaScript/TypeScript, and Rust, Logfire works with all OpenTelemetry-compatible languages. Logfire integrates with many popular Python libraries including FastAPI, OpenAI and Pydantic itself, so you can use Logfire to monitor Pydantic validations and understand why some inputs fail validation: ```python {title="Monitoring Pydantic with Logfire" test="skip"} from datetime import datetime import logfire from pydantic import BaseModel logfire.configure() logfire.instrument_pydantic() # (1)! class Delivery(BaseModel): timestamp: datetime dimensions: tuple[int, int] # this will record details of a successful validation to logfire m = Delivery(timestamp='2020-01-02T03:04:05Z', dimensions=['10', '20']) print(repr(m.timestamp)) #> datetime.datetime(2020, 1, 2, 3, 4, 5, tzinfo=TzInfo(UTC)) print(m.dimensions) #> (10, 20) Delivery(timestamp='2020-01-02T03:04:05Z', dimensions=['10']) # (2)! ``` 1. Set logfire record all both successful and failed validations, use `record='failure'` to only record failed validations, [learn more](https://logfire.pydantic.dev/docs/integrations/pydantic/). 2. This will raise a `ValidationError` since there are too few `dimensions`, details of the input data and validation errors will be recorded in Logfire. Would give you a view like this in the Logfire platform: [![Logfire Pydantic Integration](img/logfire-pydantic-integration.png)](https://logfire.pydantic.dev/docs/guides/web-ui/live/) This is just a toy example, but hopefully makes clear the potential value of instrumenting a more complex application. **[Learn more about Pydantic Logfire](https://logfire.pydantic.dev/docs/)** **Sign up for our newsletter, *The Pydantic Stack*, with updates & tutorials on Pydantic, Logfire, and Pydantic AI:**
## Why use Pydantic? * **Powered by type hints** — with Pydantic, schema validation and serialization are controlled by type annotations; less to learn, less code to write, and integration with your IDE and static analysis tools. [Learn more…](why.md#type-hints) * **Speed** — Pydantic's core validation logic is written in Rust. As a result, Pydantic is among the fastest data validation libraries for Python. [Learn more…](why.md#performance) * **JSON Schema** — Pydantic models can emit JSON Schema, allowing for easy integration with other tools. [Learn more…](why.md#json-schema) * **Strict** and **Lax** mode — Pydantic can run in either strict mode (where data is not converted) or lax mode where Pydantic tries to coerce data to the correct type where appropriate. [Learn more…](why.md#strict-lax) * **Dataclasses**, **TypedDicts** and more — Pydantic supports validation of many standard library types including `dataclass` and `TypedDict`. [Learn more…](why.md#dataclasses-typeddict-more) * **Customisation** — Pydantic allows custom validators and serializers to alter how data is processed in many powerful ways. [Learn more…](why.md#customisation) * **Ecosystem** — around 8,000 packages on PyPI use Pydantic, including massively popular libraries like *FastAPI*, *huggingface*, *Django Ninja*, *SQLModel*, & *LangChain*. [Learn more…](why.md#ecosystem) * **Battle tested** — Pydantic is downloaded over 550M times/month and is used by all FAANG companies and 20 of the 25 largest companies on NASDAQ. If you're trying to do something with Pydantic, someone else has probably already done it. [Learn more…](why.md#using-pydantic) [Installing Pydantic](install.md) is as simple as: `pip install pydantic` ## Pydantic examples To see Pydantic at work, let's start with a simple example, creating a custom class that inherits from `BaseModel`: ```python {upgrade="skip" title="Validation Successful" requires="3.10"} from datetime import datetime from pydantic import BaseModel, PositiveInt class User(BaseModel): id: int # (1)! name: str = 'John Doe' # (2)! signup_ts: datetime | None # (3)! tastes: dict[str, PositiveInt] # (4)! external_data = { 'id': 123, 'signup_ts': '2019-06-01 12:22', # (5)! 'tastes': { 'wine': 9, b'cheese': 7, # (6)! 'cabbage': '1', # (7)! }, } user = User(**external_data) # (8)! print(user.id) # (9)! #> 123 print(user.model_dump()) # (10)! """ { 'id': 123, 'name': 'John Doe', 'signup_ts': datetime.datetime(2019, 6, 1, 12, 22), 'tastes': {'wine': 9, 'cheese': 7, 'cabbage': 1}, } """ ``` 1. `id` is of type `int`; the annotation-only declaration tells Pydantic that this field is required. Strings, bytes, or floats will be coerced to integers if possible; otherwise an exception will be raised. 2. `name` is a string; because it has a default, it is not required. 3. `signup_ts` is a [`datetime`][datetime.datetime] field that is required, but the value `None` may be provided; Pydantic will process either a [Unix timestamp](https://en.wikipedia.org/wiki/Unix_time) integer (e.g. `1496498400`) or a string representing the date and time. 4. `tastes` is a dictionary with string keys and positive integer values. The `PositiveInt` type is shorthand for `Annotated[int, annotated_types.Gt(0)]`. 5. The input here is an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) formatted datetime, but Pydantic will convert it to a [`datetime`][datetime.datetime] object. 6. The key here is `bytes`, but Pydantic will take care of coercing it to a string. 7. Similarly, Pydantic will coerce the string `'1'` to the integer `1`. 8. We create instance of `User` by passing our external data to `User` as keyword arguments. 9. We can access fields as attributes of the model. 10. We can convert the model to a dictionary with [`model_dump()`][pydantic.BaseModel.model_dump]. If validation fails, Pydantic will raise an error with a breakdown of what was wrong: ```python {upgrade="skip" title="Validation Error" test="skip" lint="skip"} # continuing the above example... from datetime import datetime from pydantic import BaseModel, PositiveInt, ValidationError class User(BaseModel): id: int name: str = 'John Doe' signup_ts: datetime | None tastes: dict[str, PositiveInt] external_data = {'id': 'not an int', 'tastes': {}} # (1)! try: User(**external_data) # (2)! except ValidationError as e: print(e.errors()) """ [ { 'type': 'int_parsing', 'loc': ('id',), 'msg': 'Input should be a valid integer, unable to parse string as an integer', 'input': 'not an int', 'url': 'https://errors.pydantic.dev/2/v/int_parsing', }, { 'type': 'missing', 'loc': ('signup_ts',), 'msg': 'Field required', 'input': {'id': 'not an int', 'tastes': {}}, 'url': 'https://errors.pydantic.dev/2/v/missing', }, ] """ ``` 1. The input data is wrong here — `id` is not a valid integer, and `signup_ts` is missing. 2. Trying to instantiate `User` will raise a [`ValidationError`][pydantic_core.ValidationError] with a list of errors. ## Who is using Pydantic? Hundreds of organisations and packages are using Pydantic. Some of the prominent companies and organizations around the world who are using Pydantic include: {{ organisations }} For a more comprehensive list of open-source projects using Pydantic see the [list of dependents on github](https://github.com/pydantic/pydantic/network/dependents), or you can find some awesome projects using Pydantic in [awesome-pydantic](https://github.com/Kludex/awesome-pydantic). pydantic-pydantic-ba0aa01/docs/install.md000066400000000000000000000041451517143232300205320ustar00rootroot00000000000000Installation is as simple as: === "pip" ```bash pip install pydantic ``` === "uv" ```bash uv add pydantic ``` Pydantic has a few dependencies: * [`pydantic-core`](https://pypi.org/project/pydantic-core/): Core validation logic for Pydantic written in Rust. * [`typing-extensions`](https://pypi.org/project/typing-extensions/): Backport of the standard library [typing][] module. * [`annotated-types`](https://pypi.org/project/annotated-types/): Reusable constraint types to use with [`typing.Annotated`][]. If you've got Python 3.9+ and `pip` installed, you're good to go. Pydantic is also available on [conda](https://www.anaconda.com) under the [conda-forge](https://conda-forge.org) channel: ```bash conda install pydantic -c conda-forge ``` ## Optional dependencies Pydantic has the following optional dependencies: * `email`: Email validation provided by the [email-validator](https://pypi.org/project/email-validator/) package. * `timezone`: Fallback IANA time zone database provided by the [tzdata](https://pypi.org/project/tzdata/) package. To install optional dependencies along with Pydantic: === "pip" ```bash # with the `email` extra: pip install 'pydantic[email]' # or with `email` and `timezone` extras: pip install 'pydantic[email,timezone]' ``` === "uv" ```bash # with the `email` extra: uv add 'pydantic[email]' # or with `email` and `timezone` extras: uv add 'pydantic[email,timezone]' ``` Of course, you can also install requirements manually with `pip install email-validator tzdata`. ## Install from repository And if you prefer to install Pydantic directly from the repository: === "pip" ```bash pip install 'git+https://github.com/pydantic/pydantic@main' # or with `email` and `timezone` extras: pip install 'git+https://github.com/pydantic/pydantic@main#egg=pydantic[email,timezone]' ``` === "uv" ```bash uv add 'git+https://github.com/pydantic/pydantic@main' # or with `email` and `timezone` extras: uv add 'git+https://github.com/pydantic/pydantic@main#egg=pydantic[email,timezone]' ``` pydantic-pydantic-ba0aa01/docs/integrations/000077500000000000000000000000001517143232300212445ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/docs/integrations/aws_lambda.md000066400000000000000000000157521517143232300236720ustar00rootroot00000000000000`pydantic` integrates well with AWS Lambda functions. In this guide, we'll discuss how to setup `pydantic` for an AWS Lambda function. ## Installing Python libraries for AWS Lambda functions There are many ways to utilize Python libraries in AWS Lambda functions. As outlined in the [AWS Lambda documentation](https://docs.aws.amazon.com/lambda/latest/dg/lambda-python.html), the most common approaches include: * Using a [`.zip` file archive](https://docs.aws.amazon.com/lambda/latest/dg/python-package.html) to package your code and dependencies * Using [AWS Lambda Layers](https://docs.aws.amazon.com/lambda/latest/dg/python-layers.html) to share libraries across multiple functions * Using a [container image](https://docs.aws.amazon.com/lambda/latest/dg/python-image.html) to package your code and dependencies All of these approaches can be used with `pydantic`. The best approach for you will depend on your specific requirements and constraints. We'll cover the first two cases more in-depth here, as dependency management with a container image is more straightforward. If you're using a container image, you might find [this comment](https://github.com/pydantic/pydantic/issues/6557#issuecomment-1699456562) helpful for installing `pydantic`. !!! tip If you use `pydantic` across multiple functions, you may want to consider AWS Lambda Layers, which support seamless sharing of libraries across multiple functions. Regardless of the dependencies management approach you choose, it's beneficial to adhere to these guidelines to ensure a smooth dependency management process. ## Installing `pydantic` for AWS Lambda functions When you're building your `.zip` file archive with your code and dependencies or organizing your `.zip` file for a Lambda Layer, you'll likely use a local virtual environment to install and manage your dependencies. This can be a bit tricky if you're using `pip` because `pip` installs wheels compiled for your local platform, which may not be compatible with the Lambda environment. Thus, we suggest you use a command similar to the following: ```bash pip install \ --platform manylinux2014_x86_64 \ # (1)! --target= \ # (2)! --implementation cp \ # (3)! --python-version 3.10 \ # (4)! --only-binary=:all: \ # (5)! --upgrade pydantic # (6)! ``` 1. Use the platform corresponding to your Lambda runtime. 2. Specify the directory where you want to install the package (often `python` for Lambda Layers). 3. Use the CPython implementation. 4. The Python version must be compatible with the Lambda runtime. 5. This flag ensures that the package is installed pre-built binary wheels. 6. The latest version of `pydantic` will be installed. ## Troubleshooting ### Missing `pydantic_core` module The ```output no module named `pydantic_core._pydantic_core` ``` error is a common issue that indicates you have installed `pydantic` incorrectly. To debug this issue, you can try the following steps (before the failing import): 1. Check the contents of the installed `pydantic-core` package. Are the compiled library and its type stubs both present? ```python {test="skip" lint="skip"} from importlib.metadata import files print([file for file in files('pydantic-core') if file.name.startswith('_pydantic_core')]) """ [PackagePath('pydantic_core/_pydantic_core.pyi'), PackagePath('pydantic_core/_pydantic_core.cpython-312-x86_64-linux-gnu.so')] """ ``` You should expect to see two files like those printed above. The compiled library file should have the `.so` or `.pyd` extension with a name that varies according to the OS and Python version. 2. Check that your lambda's Python version is compatible with the compiled library version found above. ```python {test="skip" lint="skip"} import sysconfig print(sysconfig.get_config_var("EXT_SUFFIX")) #> '.cpython-312-x86_64-linux-gnu.so' ``` You should expect to see the same suffix here as the compiled library, for example here we see this suffix `.cpython-312-x86_64-linux-gnu.so` indeed matches `_pydantic_core.cpython-312-x86_64-linux-gnu.so`. If these two checks do not match, your build steps have not installed the correct native code for your lambda's target platform. You should adjust your build steps to change the version of the installed library which gets installed. Most likely errors: * Your OS or CPU architecture is mismatched (e.g. darwin vs x86_64-linux-gnu). Try passing correct `--platform` argument to `pip install` when installing your lambda dependencies, or build inside a linux docker container for the correct platform. Possible platforms at the moment include `--platform manylinux2014_x86_64` or `--platform manylinux2014_aarch64`, but these may change with a future Pydantic major release. * Your Python version is mismatched (e.g. `cpython-310` vs `cpython-312`). Try passing correct `--python-version` argument to `pip install`, or otherwise change the Python version used on your build. ### No package metadata was found for `email-validator` Pydantic uses `version` from `importlib.metadata` to [check what version](https://github.com/pydantic/pydantic/pull/6033) of `email-validator` is installed. This package versioning mechanism is somewhat incompatible with AWS Lambda, even though it's the industry standard for versioning packages in Python. There are a few ways to fix this issue: If you're deploying your lambda with the serverless framework, it's likely that the appropriate metadata for the `email-validator` package is not being included in your deployment package. Tools like [`serverless-python-requirements`](https://github.com/serverless/serverless-python-requirements/tree/master) remove metadata to reduce package size. You can fix this issue by setting the `slim` setting to false in your `serverless.yml` file: ```yaml pythonRequirements: dockerizePip: non-linux slim: false fileName: requirements.txt ``` You can read more about this fix, and other `slim` settings that might be relevant in this [blog post](https://biercoff.com/how-to-fix-package-not-found-error-importlib-metadata/). If you're using a `.zip` archive for your code and/or dependencies, make sure that your package contains the required version metadata. To do this, make sure you include the `dist-info` directory in your `.zip` archive for the `email-validator` package. This issue has been reported for other popular python libraries like [`jsonschema`](https://github.com/python-jsonschema/jsonschema/issues/584), so you can read more about the issue and potential fixes there as well. ## Extra Resources ### More Debugging Tips If you're still struggling with installing `pydantic` for your AWS Lambda, you might consult with [this issue](https://github.com/pydantic/pydantic/issues/6557), which covers a variety of problems and solutions encountered by other developers. ### Validating `event` and `context` data Check out our [blog post](https://pydantic.dev/articles/lambda-intro) to learn more about how to use `pydantic` to validate `event` and `context` data in AWS Lambda functions. pydantic-pydantic-ba0aa01/docs/integrations/datamodel_code_generator.md000066400000000000000000000047161517143232300265700ustar00rootroot00000000000000# Code Generation with datamodel-code-generator The [datamodel-code-generator](https://github.com/koxudaxi/datamodel-code-generator/) project is a library and command-line utility to generate pydantic models from just about any data source, including: * OpenAPI 3 (YAML/JSON) * JSON Schema * JSON/YAML/CSV Data (which will be converted to JSON Schema) * Python dictionary (which will be converted to JSON Schema) * GraphQL schema Whenever you find yourself with any data convertible JSON but without pydantic models, this tool will allow you to generate type-safe model hierarchies on demand. ## Installation ```bash pip install datamodel-code-generator ``` ## Example In this case, datamodel-code-generator creates pydantic models from a JSON Schema file. ```bash datamodel-codegen --input person.json --input-file-type jsonschema --output model.py ``` person.json: ```json { "$id": "person.json", "$schema": "http://json-schema.org/draft-07/schema#", "title": "Person", "type": "object", "properties": { "first_name": { "type": "string", "description": "The person's first name." }, "last_name": { "type": "string", "description": "The person's last name." }, "age": { "description": "Age in years.", "type": "integer", "minimum": 0 }, "pets": { "type": "array", "items": [ { "$ref": "#/definitions/Pet" } ] }, "comment": { "type": "null" } }, "required": [ "first_name", "last_name" ], "definitions": { "Pet": { "properties": { "name": { "type": "string" }, "age": { "type": "integer" } } } } } ``` model.py: ```python {upgrade="skip" requires="3.10"} # generated by datamodel-codegen: # filename: person.json # timestamp: 2020-05-19T15:07:31+00:00 from __future__ import annotations from typing import Any from pydantic import BaseModel, Field, conint class Pet(BaseModel): name: str | None = None age: int | None = None class Person(BaseModel): first_name: str = Field(description="The person's first name.") last_name: str = Field(description="The person's last name.") age: conint(ge=0) | None = Field(None, description='Age in years.') pets: list[Pet] | None = None comment: Any | None = None ``` More information can be found on the [official documentation](https://koxudaxi.github.io/datamodel-code-generator/) pydantic-pydantic-ba0aa01/docs/integrations/devtools.md000066400000000000000000000025261517143232300234320ustar00rootroot00000000000000!!! note **Admission:** I (the primary developer of Pydantic) also develop python-devtools. [python-devtools](https://python-devtools.helpmanual.io/) (`pip install devtools`) provides a number of tools which are useful during Python development, including `debug()` an alternative to `print()` which formats output in a way which should be easier to read than `print` as well as giving information about which file/line the print statement is on and what value was printed. Pydantic integrates with *devtools* by implementing the `__pretty__` method on most public classes. In particular `debug()` is useful when inspecting models: ```python {test="no-print-intercept"} from datetime import datetime from devtools import debug from pydantic import BaseModel class Address(BaseModel): street: str country: str lat: float lng: float class User(BaseModel): id: int name: str signup_ts: datetime friends: list[int] address: Address user = User( id='123', name='John Doe', signup_ts='2019-06-01 12:22', friends=[1234, 4567, 7890], address=dict(street='Testing', country='uk', lat=51.5, lng=0), ) debug(user) print('\nshould be much easier read than:\n') print('user:', user) ``` Will output in your terminal: {{ devtools_example }} !!! note `python-devtools` doesn't yet support Python 3.13. pydantic-pydantic-ba0aa01/docs/integrations/documentation.md000066400000000000000000000027001517143232300244360ustar00rootroot00000000000000Pydantic uses [MkDocs](https://www.mkdocs.org/) for documentation, together with [mkdocstrings](https://mkdocstrings.github.io/). As such, you can make use of Pydantic's Sphinx object inventory to cross-reference the Pydantic API documentation. === "Sphinx" In your [Sphinx configuration](https://www.sphinx-doc.org/en/master/usage/configuration.html), add the following to the [`intersphinx` extension configuration](https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html#configuration): ```python {test="skip"} intersphinx_mapping = { 'pydantic': ('https://docs.pydantic.dev/latest', None), # (1)! } ``` 1. You can also use `dev` instead of `latest` to target the latest documentation build, up to date with the [`main`](https://github.com/pydantic/pydantic/tree/main) branch. === "mkdocstrings" In your [MkDocs configuration](https://www.mkdocs.org/user-guide/configuration/), add the following import to your [mkdocstrings plugin configuration](https://mkdocstrings.github.io/usage/#cross-references-to-other-projects-inventories): ```yaml plugins: - mkdocstrings: handlers: python: import: - https://docs.pydantic.dev/latest/objects.inv # (1)! ``` 1. You can also use `dev` instead of `latest` to target the latest documentation build, up to date with the [`main`](https://github.com/pydantic/pydantic/tree/main) branch. pydantic-pydantic-ba0aa01/docs/integrations/hypothesis.md000066400000000000000000000017261517143232300237730ustar00rootroot00000000000000[Hypothesis](https://hypothesis.readthedocs.io/) is the Python library for [property-based testing](https://increment.com/testing/in-praise-of-property-based-testing/). Hypothesis can infer how to construct type-annotated classes, and supports builtin types, many standard library types, and generic types from the [`typing`](https://docs.python.org/3/library/typing.html) and [`typing_extensions`](https://pypi.org/project/typing-extensions/) modules by default. Pydantic v2.0 drops built-in support for Hypothesis and no more ships with the integrated Hypothesis plugin. !!! warning We are temporarily removing the Hypothesis plugin in favor of studying a different mechanism. For more information, see the issue [annotated-types/annotated-types#37](https://github.com/annotated-types/annotated-types/issues/37). The Hypothesis plugin may be back in a future release. Subscribe to [pydantic/pydantic#4682](https://github.com/pydantic/pydantic/issues/4682) for updates. pydantic-pydantic-ba0aa01/docs/integrations/linting.md000066400000000000000000000006251517143232300232350ustar00rootroot00000000000000## Flake8 plugin If using Flake8 in your project, a [plugin](https://pypi.org/project/flake8-pydantic/) is available and can be installed using the following: ```bash pip install flake8-pydantic ``` The lint errors provided by this plugin are namespaced under the `PYDXXX` code. To ignore some unwanted rules, the Flake8 configuration can be adapted: ```ini [flake8] extend-ignore = PYD001,PYD002 ``` pydantic-pydantic-ba0aa01/docs/integrations/llms.md000066400000000000000000000015541517143232300225420ustar00rootroot00000000000000The Pydantic documentation is available in the [llms.txt](https://llmstxt.org/) format. This format is defined in Markdown and suited for large language models. Two formats are available: * [llms.txt](https://docs.pydantic.dev/latest/llms.txt): a file containing a brief description of the project, along with links to the different sections of the documentation. The structure of this file is described in details in the [format documentation](https://llmstxt.org/#format). * [llms-full.txt](https://docs.pydantic.dev/latest/llms-full.txt): Similar to the `llms.txt` file, but every link content is included. Note that this file may be too large for some LLMs. As of today, these files *cannot* be natively leveraged by LLM frameworks or IDEs. Alternatively, a [MCP server](https://modelcontextprotocol.io/) can be implemented to properly parse the `llms.txt` file. pydantic-pydantic-ba0aa01/docs/integrations/logfire.md000066400000000000000000000046251517143232300232240ustar00rootroot00000000000000Pydantic integrates seamlessly with **Pydantic Logfire**, an observability platform built by us on the same belief as our open source library — that the most powerful tools can be easy to use. ## Getting Started Logfire has an out-of-the-box Pydantic integration that lets you understand the data passing through your Pydantic models and get analytics on validations. For existing Pydantic users, it delivers unparalleled insights into your usage of Pydantic models. [Getting started](https://logfire.pydantic.dev/docs/) with Logfire can be done in three simple steps: 1. Set up your Logfire account. 2. Install the Logfire SDK. 3. Instrument your project. ### Basic Usage Once you've got Logfire set up, you can start using it to monitor your Pydantic models and get insights into your data validation: ```python {test="skip"} from datetime import date import logfire from pydantic import BaseModel logfire.configure() # (1)! class User(BaseModel): name: str country_code: str dob: date user = User(name='Anne', country_code='USA', dob='2000-01-01') logfire.info('user processed: {user!r}', user=user) # (2)! ``` 1. The `logfire.configure()` call is all you need to instrument your project with Logfire. 2. The `logfire.info()` call logs the `user` object to Logfire, with builtin support for Pydantic models. ![basic pydantic logfire usage](../img/basic_logfire.png) ### Pydantic Instrumentation You can even record information about the validation process automatically by using the builtin [Pydantic integration](https://logfire.pydantic.dev/docs/why-logfire/pydantic/): ```python {test="skip"} from datetime import date import logfire from pydantic import BaseModel logfire.configure() logfire.instrument_pydantic() # (1)! class User(BaseModel): name: str country_code: str dob: date User(name='Anne', country_code='USA', dob='2000-01-01') User(name='David', country_code='GBR', dob='invalid-dob') ``` 1. The `logfire.instrument_pydantic()` call automatically logs validation information for all Pydantic models in your project. You'll see each successful and failed validation logged in Logfire: ![logfire instrumentation](../img/logfire_instrument.png) And you can investigate each of the corresponding spans to get validation details: ![logfire span details](../img/logfire_span.png) pydantic-pydantic-ba0aa01/docs/integrations/mypy.md000066400000000000000000000163541517143232300225750ustar00rootroot00000000000000Pydantic works well with [mypy](http://mypy-lang.org) right out of the box. However, Pydantic also ships with a mypy plugin that adds a number of important Pydantic-specific features that improve its ability to type-check your code. For example, consider the following script: ```python {test="skip" linenums="1"} from datetime import datetime from typing import Optional from pydantic import BaseModel class Model(BaseModel): age: int first_name = 'John' last_name: Optional[str] = None signup_ts: Optional[datetime] = None list_of_ints: list[int] m = Model(age=42, list_of_ints=[1, '2', b'3']) print(m.middle_name) # not a model field! Model() # will raise a validation error for age and list_of_ints ``` Without any special configuration, mypy does not catch the [missing model field annotation](../errors/usage_errors.md#model-field-missing-annotation) and errors about the `list_of_ints` argument which Pydantic parses correctly: ```output 15: error: List item 1 has incompatible type "str"; expected "int" [list-item] 15: error: List item 2 has incompatible type "bytes"; expected "int" [list-item] 16: error: "Model" has no attribute "middle_name" [attr-defined] 17: error: Missing named argument "age" for "Model" [call-arg] 17: error: Missing named argument "list_of_ints" for "Model" [call-arg] ``` But [with the plugin enabled](#enabling-the-plugin), it gives the correct errors: ```output 9: error: Untyped fields disallowed [pydantic-field] 16: error: "Model" has no attribute "middle_name" [attr-defined] 17: error: Missing named argument "age" for "Model" [call-arg] 17: error: Missing named argument "list_of_ints" for "Model" [call-arg] ``` With the pydantic mypy plugin, you can fearlessly refactor your models knowing mypy will catch any mistakes if your field names or types change. Note that mypy already supports some features without using the Pydantic plugin, such as synthesizing a `__init__` method for Pydantic models and dataclasses. See the [mypy plugin capabilities](#mypy-plugin-capabilities) for a list of additional features. The Pydantic mypy plugin is tested against the latest mypy version. Older versions might work but won't be tested. ## Enabling the Plugin To enable the plugin, just add `pydantic.mypy` to the list of plugins in your [mypy config file](https://mypy.readthedocs.io/en/latest/config_file.html): === "`mypy.ini`" ```ini [mypy] plugins = pydantic.mypy ``` === "`pyproject.toml`" ```toml [tool.mypy] plugins = ['pydantic.mypy'] ``` !!! note If you're using `pydantic.v1` models, you'll need to add `pydantic.v1.mypy` to your list of plugins. See the [plugin configuration](#configuring-the-plugin) for more details. ## Mypy plugin capabilities ### Generate a `__init__` signature for Pydantic models * Any required fields that don't have dynamically-determined aliases will be included as required keyword arguments. * If the [`validate_by_name`][pydantic.ConfigDict.validate_by_name] model configuration value is set to `True`, the generated signature will use the field names rather than aliases. * The [`init_forbid_extra`](#init_forbid_extra) and [`init_typed`](#init_typed) plugin configuration values can further fine-tune the synthesized `__init__` method. ### Generate a typed signature for `model_construct` * The [`model_construct`][pydantic.BaseModel.model_construct] method is an alternative to model validation when input data is known to be valid and should not be parsed (see the [documentation](../concepts/models.md#creating-models-without-validation)). Because this method performs no runtime validation, static checking is important to detect errors. ### Support for frozen models * If the [`frozen`][pydantic.ConfigDict.frozen] configuration is set to `True`, you will get an error if you try mutating a model field (see [faux immutability](../concepts/models.md#faux-immutability)) ### Respect the type of the `Field`'s `default` and `default_factory` * Field with both a `default` and a `default_factory` will result in an error during static checking. * The type of the `default` and `default_factory` value must be compatible with the one of the field. ### Warn about the use of untyped fields * While defining a field without an annotation will result in a [runtime error](../errors/usage_errors.md#model-field-missing-annotation), the plugin will also emit a type checking error. ### Prevent the use of required dynamic aliases See the documentation of the [`warn_required_dynamic_aliases`](#warn_required_dynamic_aliases) plugin configuration value. ## Configuring the Plugin To change the values of the plugin settings, create a section in your mypy config file called `[pydantic-mypy]`, and add any key-value pairs for settings you want to override. A configuration file with all plugin strictness flags enabled (and some other mypy strictness flags, too) might look like: === "`mypy.ini`" ```ini [mypy] plugins = pydantic.mypy follow_imports = silent warn_redundant_casts = True warn_unused_ignores = True disallow_any_generics = True no_implicit_reexport = True disallow_untyped_defs = True [pydantic-mypy] init_forbid_extra = True init_typed = True warn_required_dynamic_aliases = True ``` === "`pyproject.toml`" ```toml [tool.mypy] plugins = ["pydantic.mypy"] follow_imports = "silent" warn_redundant_casts = true warn_unused_ignores = true disallow_any_generics = true no_implicit_reexport = true disallow_untyped_defs = true [tool.pydantic-mypy] init_forbid_extra = true init_typed = true warn_required_dynamic_aliases = true ``` ### `init_typed` Because Pydantic performs [data conversion](../concepts/models.md#data-conversion) by default, the following is still valid at runtime: ```python {test="skip" lint="skip"} class Model(BaseModel): a: int Model(a='1') ``` For this reason, the plugin will use [`Any`][typing.Any] for field annotations when synthesizing the `__init__` method, unless `init_typed` is set or [strict mode](../concepts/strict_mode.md) is enabled on the model. ### `init_forbid_extra` By default, Pydantic allows (and ignores) any extra provided argument: ```python {test="skip" lint="skip"} class Model(BaseModel): a: int = 1 Model(unrelated=2) ``` For this reason, the plugin will add an extra `**kwargs: Any` parameter when synthesizing the `__init__` method, unless `init_forbid_extra` is set or the [`extra`][pydantic.ConfigDict.extra] is set to `'forbid'`. ### `warn_required_dynamic_aliases` Whether to error when using a dynamically-determined alias or alias generator on a model with [`validate_by_name`][pydantic.ConfigDict.validate_by_name] set to `False`. If such aliases are present, mypy cannot properly type check calls to `__init__`. In this case, it will default to treating all arguments as not required. !!! note "Compatibility with `Any` being disallowed" Some mypy configuration options (such as [`disallow_any_explicit`](https://mypy.readthedocs.io/en/stable/config_file.html#confval-disallow_any_explicit)) will error because the synthesized `__init__` method contains [`Any`][typing.Any] annotations. To circumvent the issue, you will have to enable both `init_forbid_extra` and `init_typed`. pydantic-pydantic-ba0aa01/docs/integrations/pycharm.md000066400000000000000000000016661517143232300232420ustar00rootroot00000000000000While pydantic will work well with any IDE out of the box, a [PyCharm plugin](https://plugins.jetbrains.com/plugin/12861-pydantic) offering improved pydantic integration is available on the JetBrains Plugins Repository for PyCharm. You can install the plugin for free from the plugin marketplace (PyCharm's Preferences -> Plugin -> Marketplace -> search "pydantic"). The plugin currently supports the following features: * For `pydantic.BaseModel.__init__`: * Inspection * Autocompletion * Type-checking * For fields of `pydantic.BaseModel`: * Refactor-renaming fields updates `__init__` calls, and affects sub- and super-classes * Refactor-renaming `__init__` keyword arguments updates field names, and affects sub- and super-classes More information can be found on the [official plugin page](https://plugins.jetbrains.com/plugin/12861-pydantic) and [Github repository](https://github.com/koxudaxi/pydantic-pycharm-plugin). pydantic-pydantic-ba0aa01/docs/integrations/pyrefly.md000066400000000000000000000043161517143232300232640ustar00rootroot00000000000000[Pyrefly](https://pyrefly.org/) is a Python type checker and language server with built-in support for a number of Pydantic-specific features. This support works out-of-the-box with Pydantic and Pyrefly installed, with no additional configuration needed. Pyrefly is available as both an [IDE extension](https://pyrefly.org/en/docs/IDE/) and a [command-line type checker](https://pyrefly.org/en/docs/installation/). ## IDE extension Pyrefly gives you IDE features such as go-to-definition and autocomplete on your Pydantic models. Here’s an example of signature help, powered by Pyrefly’s understanding of the Pydantic-specific `validation_alias` keyword: ![Signature help with the Pyrefly IDE extension](../img/pyrefly.png) As you type `Model()`, Pyrefly hints that you need to use the name `x_` to populate the `x` field. ## Type checker Pyrefly can also catch errors in your code before you run it. Consider the following example: ```python {test="skip" linenums="1"} from pydantic import BaseModel, ConfigDict class Model1(BaseModel, frozen=True): x: int class Model2(BaseModel): model_config = ConfigDict(frozen=True) x: int model1 = Model1(x=0) model1.x = 1 # validation error: mutating a frozen field model2 = Model2(x=0) model2.x = 1 # validation error: mutating a frozen field ``` Since `Model1` declares that it is frozen using a [standard type system feature](https://typing.python.org/en/latest/spec/dataclasses.html#the-dataclass-transform-decorator), any type checker of your choice will catch the validation error from mutating `model1.x`. However, a type checker without special support for the Pydantic `ConfigDict` class will miss the validation error from mutating `model2.x`. Pyrefly catches both errors: ```output ERROR Cannot set field `x` [read-only] --> foo.py:11:1 | 11 | model1.x = 1 # validation error: mutating a frozen field | ^^^^^^^^ | This field belongs to a frozen Pydantic model ERROR Cannot set field `x` [read-only] --> foo.py:14:1 | 14 | model2.x = 1 # validation error: mutating a frozen field | ^^^^^^^^ | This field belongs to a frozen Pydantic model ``` See the [Pyrefly documentation](https://pyrefly.org/en/docs/pydantic/ ) for more information. pydantic-pydantic-ba0aa01/docs/integrations/rich.md000066400000000000000000000005501517143232300225130ustar00rootroot00000000000000Pydantic models may be printed with the [Rich](https://github.com/willmcgugan/rich) library which will add additional formatting and color to the output. Here's an example: ![Printing Pydantic models with Rich](../img/rich_pydantic.png) See the Rich documentation on [pretty printing](https://rich.readthedocs.io/en/latest/pretty.html) for more information. pydantic-pydantic-ba0aa01/docs/integrations/visual_studio_code.md000066400000000000000000000251051517143232300254550ustar00rootroot00000000000000Pydantic works well with any editor or IDE out of the box because it's made on top of standard Python type annotations. When using [Visual Studio Code (VS Code)](https://code.visualstudio.com/), there are some **additional editor features** supported, comparable to the ones provided by the [PyCharm plugin](../integrations/pycharm.md). This means that you will have **autocompletion** (or "IntelliSense") and **error checks** for types and required arguments even while creating new Pydantic model instances. ![pydantic autocompletion in VS Code](../img/vs_code_01.png) ## Configure VS Code To take advantage of these features, you need to make sure you configure VS Code correctly, using the recommended settings. In case you have a different configuration, here's a short overview of the steps. ### Install Pylance You should use the [Pylance](https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance) extension for VS Code. It is the recommended, next-generation, official VS Code plug-in for Python. Pylance is installed as part of the [Python Extension for VS Code](https://marketplace.visualstudio.com/items?itemName=ms-python.python) by default, so it should probably just work. Otherwise, you can double check it's installed and enabled in your editor. ### Configure your environment Then you need to make sure your editor knows the [Python environment](https://code.visualstudio.com/docs/python/python-tutorial#_install-and-use-packages) (probably a virtual environment) for your Python project. This would be the environment in where you installed Pydantic. ### Configure Pylance With the default configurations, you will get support for autocompletion, but Pylance might not check for type errors. You can enable type error checks from Pylance with these steps: * Open the "User Settings" * Search for `Type Checking Mode` * You will find an option under `Python › Analysis: Type Checking Mode` * Set it to `basic` or `strict` (by default it's `off`) ![Type Checking Mode set to strict in VS Code](../img/vs_code_02.png) Now you will not only get autocompletion when creating new Pydantic model instances but also error checks for **required arguments**. ![Required arguments error checks in VS Code](../img/vs_code_03.png) And you will also get error checks for **invalid data types**. ![Invalid data types error checks in VS Code](../img/vs_code_04.png) !!! note "Technical Details" Pylance is the VS Code extension, it's closed source, but free to use. Underneath, Pylance uses an open source tool (also from Microsoft) called [Pyright](https://github.com/microsoft/pyright) that does all the heavy lifting. You can read more about it in the [Pylance Frequently Asked Questions](https://github.com/microsoft/pylance-release/blob/main/FAQ.md#what-is-the-relationship-between-pylance-pyright-and-the-python-extension). ### Configure mypy You might also want to configure mypy in VS Code to get mypy error checks inline in your editor (alternatively/additionally to Pylance). This would include the errors detected by the [Pydantic mypy plugin](../integrations/mypy.md), if you configured it. To enable mypy in VS Code, do the following: * Open the "User Settings" * Search for `Mypy Enabled` * You will find an option under `Python › Linting: Mypy Enabled` * Check the box (by default it's unchecked) ![mypy enabled in VS Code](../img/vs_code_05.png) ## Tips and tricks Here are some additional tips and tricks to improve your developer experience when using VS Code with Pydantic. ### Strict errors The way this additional editor support works is that Pylance will treat your Pydantic models as if they were Python's pure `dataclasses`. And it will show **strict type error checks** about the data types passed in arguments when creating a new Pydantic model instance. In this example you can see that it shows that a `str` of `'23'` is not a valid `int` for the argument `age`. ![VS Code strict type errors](../img/vs_code_06.png) It would expect `age=23` instead of `age='23'`. Nevertheless, the design, and one of the main features of Pydantic, is that it is very **lenient with data types**. It will actually accept the `str` with value `'23'` and will convert it to an `int` with value `23`. These strict error checks are **very useful** most of the time and can help you **detect many bugs early**. But there are cases, like with `age='23'`, where they could be inconvenient by reporting a "false positive" error. --- This example above with `age='23'` is intentionally simple, to show the error and the differences in types. But more common cases where these strict errors would be inconvenient would be when using more sophisticated data types, like `int` values for `datetime` fields, or `dict` values for Pydantic sub-models. For example, this is valid for Pydantic: ```python {hl_lines="12 17"} from pydantic import BaseModel class Knight(BaseModel): title: str age: int color: str = 'blue' class Quest(BaseModel): title: str knight: Knight quest = Quest( title='To seek the Holy Grail', knight={'title': 'Sir Lancelot', 'age': 23} ) ``` The type of the field `knight` is declared with the class `Knight` (a Pydantic model) and the code is passing a literal `dict` instead. This is still valid for Pydantic, and the `dict` would be automatically converted to a `Knight` instance. Nevertheless, it would be detected as a type error: ![VS Code strict type errors with model](../img/vs_code_07.png) In those cases, there are several ways to disable or ignore strict errors in very specific places, while still preserving them in the rest of the code. Below are several techniques to achieve it. #### Disable type checks in a line You can disable the errors for a specific line using a comment of: ```python # type: ignore ``` or (to be specific to pylance/pyright): ```python # pyright: ignore ``` ([pyright](https://github.com/microsoft/pyright) is the language server used by Pylance.). coming back to the example with `age='23'`, it would be: ```python {hl_lines="10"} from pydantic import BaseModel class Knight(BaseModel): title: str age: int color: str = 'blue' lancelot = Knight(title='Sir Lancelot', age='23') # pyright: ignore ``` that way Pylance and mypy will ignore errors in that line. **Pros**: it's a simple change in that line to remove errors there. **Cons**: any other error in that line will also be omitted, including type checks, misspelled arguments, required arguments not provided, etc. #### Override the type of a variable You can also create a variable with the value you want to use and declare its type explicitly with `Any`. ```python {hl_lines="1 11-12"} from typing import Any from pydantic import BaseModel class Knight(BaseModel): title: str age: int color: str = 'blue' age_str: Any = '23' lancelot = Knight(title='Sir Lancelot', age=age_str) ``` that way Pylance and mypy will interpret the variable `age_str` as if they didn't know its type, instead of knowing it has a type of `str` when an `int` was expected (and then showing the corresponding error). **Pros**: errors will be ignored only for a specific value, and you will still see any additional errors for the other arguments. **Cons**: it requires importing `Any` and a new variable in a new line for each argument that needs ignoring errors. #### Override the type of a value with `cast` The same idea from the previous example can be put on the same line with the help of `cast()`. This way, the type declaration of the value is overridden inline, without requiring another variable. ```python {hl_lines="1 11"} from typing import Any, cast from pydantic import BaseModel class Knight(BaseModel): title: str age: int color: str = 'blue' lancelot = Knight(title='Sir Lancelot', age=cast(Any, '23')) ``` `cast(Any, '23')` doesn't affect the value, it's still just `'23'`, but now Pylance and mypy will assume it is of type `Any`, which means, they will act as if they didn't know the type of the value. So, this is the equivalent of the previous example, without the additional variable. **Pros**: errors will be ignored only for a specific value, and you will still see any additional errors for the other arguments. There's no need for additional variables. **Cons**: it requires importing `Any` and `cast`, and if you are not used to using `cast()`, it could seem strange at first. ### Config in class arguments Pydantic has a rich set of [Model Configurations][pydantic.config.ConfigDict] available. These configurations can be set in an internal `class Config` on each model: ```python {hl_lines="9-10"} from pydantic import BaseModel class Knight(BaseModel): model_config = dict(frozen=True) title: str age: int color: str = 'blue' ``` or passed as keyword arguments when defining the model class: ```python {hl_lines="4"} from pydantic import BaseModel class Knight(BaseModel, frozen=True): title: str age: int color: str = 'blue' ``` The specific configuration **`frozen`** (in beta) has a special meaning. It prevents other code from changing a model instance once it's created, keeping it **"frozen"**. When using the second version to declare `frozen=True` (with **keyword arguments** in the class definition), Pylance can use it to help you check in your code and **detect errors** when something is trying to set values in a model that is "frozen". ![VS Code strict type errors with model](../img/vs_code_08.png) ## Adding a default with `Field` Pylance/pyright requires `default` to be a keyword argument to `Field` in order to infer that the field is optional. ```python from pydantic import BaseModel, Field class Knight(BaseModel): title: str = Field(default='Sir Lancelot') # this is okay age: int = Field( 23 ) # this works fine at runtime but will case an error for pyright lance = Knight() # error: Argument missing for parameter "age" ``` This is a limitation of dataclass transforms and cannot be fixed in pydantic. ## Technical Details !!! warning As a Pydantic user, you don't need the details below. Feel free to skip the rest of this section. These details are only useful for other library authors, etc. This additional editor support works by making use of the [`@dataclass_transform` decorator](https://typing.python.org/en/latest/spec/dataclasses.html#the-dataclass-transform-decorator) (introduced by [PEP 681](https://peps.python.org/pep-0681/)). The standard provides a way for libraries like Pydantic and others to tell editors and tools that they (the editors) should treat these libraries (e.g. Pydantic) as if they were [dataclasses][dataclasses], providing autocompletion, type checks, etc. pydantic-pydantic-ba0aa01/docs/internals/000077500000000000000000000000001517143232300205355ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/docs/internals/architecture.md000066400000000000000000000222051517143232300235420ustar00rootroot00000000000000!!! note This section is part of the *internals* documentation, and is partly targeted to contributors. Starting with Pydantic V2, part of the codebase is written in Rust in a separate package called `pydantic-core`. This was done partly in order to improve validation and serialization performance (with the cost of limited customization and extendibility of the internal logic). This architecture documentation will first cover how the two `pydantic` and `pydantic-core` packages interact together, then will go through the architecture specifics for various patterns (model definition, validation, serialization, JSON Schema). Usage of the Pydantic library can be divided into two parts: * Model definition, done in the `pydantic` package. * Model validation and serialization, done in the `pydantic-core` package. ## Model definition Whenever a Pydantic [`BaseModel`][pydantic.main.BaseModel] is defined, the metaclass will analyze the body of the model to collect a number of elements: * Defined annotations to build model fields (collected in the [`model_fields`][pydantic.main.BaseModel.model_fields] attribute). * Model configuration, set with [`model_config`][pydantic.main.BaseModel.model_config]. * Additional validators/serializers. * Private attributes, class variables, identification of generic parametrization, etc. ### Communicating between `pydantic` and `pydantic-core`: the core schema We then need a way to communicate the collected information from the model definition to `pydantic-core`, so that validation and serialization is performed accordingly. To do so, Pydantic uses the concept of a core schema: a structured (and serializable) Python dictionary (represented using [`TypedDict`][typing.TypedDict] definitions) describing a specific validation and serialization logic. It is the core data structure used to communicate between the `pydantic` and `pydantic-core` packages. Every core schema has a required `type` key, and extra properties depending on this `type`. The generation of a core schema is handled in a single place, by the `GenerateSchema` class (no matter if it is for a Pydantic model or anything else). !!! note It is not possible to define a custom core schema. A core schema needs to be understood by the `pydantic-core` package, and as such we only support a fixed number of core schema types. This is also part of the reason why the `GenerateSchema` isn't truly exposed and properly documented. The core schema definitions can be found in the [`pydantic_core.core_schema`][] module. In the case of a Pydantic model, a core schema will be constructed and set as the [`__pydantic_core_schema__`][pydantic.main.BaseModel.__pydantic_core_schema__] attribute. To illustrate what a core schema looks like, we will take the example of the [`bool`][pydantic_core.core_schema.bool_schema] core schema: ```python {lint="skip" test="skip"} class BoolSchema(TypedDict, total=False): type: Required[Literal['bool']] strict: bool ref: str metadata: Any serialization: SerSchema ``` When defining a Pydantic model with a boolean field: ```python from pydantic import BaseModel, Field class Model(BaseModel): foo: bool = Field(strict=True) ``` The core schema for the `foo` field will look like: ```python { 'type': 'bool', 'strict': True, } ``` As seen in the [`BoolSchema`][pydantic_core.core_schema.bool_schema] definition, the serialization logic is also defined in the core schema. If we were to define a custom serialization function for `foo` (1), the `serialization` key would look like: { .annotate } 1. For example using the [`field_serializer`][pydantic.functional_serializers.field_serializer] decorator: ```python {test="skip" lint="skip"} class Model(BaseModel): foo: bool = Field(strict=True) @field_serializer('foo', mode='plain') def serialize_foo(self, value: bool) -> Any: ... ``` ```python {lint="skip" test="skip"} { 'type': 'function-plain', 'function': , 'is_field_serializer': True, 'info_arg': False, 'return_schema': {'type': 'int'}, } ``` Note that this is also a core schema definition, just that it is only relevant for `pydantic-core` during serialization. Core schemas cover a broad scope, and are used whenever we want to communicate between the Python and Rust side. While the previous examples were related to validation and serialization, it could in theory be used for anything: error management, extra metadata, etc. ### JSON Schema generation You may have noticed that the previous serialization core schema has a `return_schema` key. This is because the core schema is also used to generate the corresponding JSON Schema. Similar to how the core schema is generated, the JSON Schema generation is handled by the [`GenerateJsonSchema`][pydantic.json_schema.GenerateJsonSchema] class. The [`generate`][pydantic.json_schema.GenerateJsonSchema.generate] method is the main entry point and is given the core schema of that model. Coming back to our `bool` field example, the [`bool_schema`][pydantic.json_schema.GenerateJsonSchema.bool_schema] method will be given the previously generated [boolean core schema][pydantic_core.core_schema.bool_schema] and will return the following JSON Schema: ```json { {"type": "boolean"} } ``` ### Customizing the core schema and JSON schema !!! abstract "Usage Documentation" [Custom types](../concepts/types.md#custom-types) [Implementing `__get_pydantic_core_schema__`](../concepts/json_schema.md#implementing-__get_pydantic_core_schema__) [Implementing `__get_pydantic_json_schema__`](../concepts/json_schema.md#implementing-__get_pydantic_json_schema__) While the `GenerateSchema` and [`GenerateJsonSchema`][pydantic.json_schema.GenerateJsonSchema] classes handle the creation of the corresponding schemas, Pydantic offers a way to customize them in some cases, following a wrapper pattern. This customization is done through the `__get_pydantic_core_schema__` and `__get_pydantic_json_schema__` methods. To understand this wrapper pattern, we will take the example of metadata classes used with [`Annotated`][typing.Annotated], where the `__get_pydantic_core_schema__` method can be used: ```python from typing import Annotated, Any from pydantic_core import CoreSchema from pydantic import GetCoreSchemaHandler, TypeAdapter class MyStrict: @classmethod def __get_pydantic_core_schema__( cls, source: Any, handler: GetCoreSchemaHandler ) -> CoreSchema: schema = handler(source) # (1)! schema['strict'] = True return schema class MyGt: @classmethod def __get_pydantic_core_schema__( cls, source: Any, handler: GetCoreSchemaHandler ) -> CoreSchema: schema = handler(source) # (2)! schema['gt'] = 1 return schema ta = TypeAdapter(Annotated[int, MyStrict(), MyGt()]) ``` 1. `MyStrict` is the first annotation to be applied. At this point, `schema = {'type': 'int'}`. 2. `MyGt` is the last annotation to be applied. At this point, `schema = {'type': 'int', 'strict': True}`. When the `GenerateSchema` class builds the core schema for `Annotated[int, MyStrict(), MyGt()]`, it will create an instance of a `GetCoreSchemaHandler` to be passed to the `MyGt.__get_pydantic_core_schema__` method. (1) { .annotate } 1. In the case of our [`Annotated`][typing.Annotated] pattern, the `GetCoreSchemaHandler` is defined in a nested way. Calling it will recursively call the other `__get_pydantic_core_schema__` methods until it reaches the `int` annotation, where a simple `{'type': 'int'}` schema is returned. The `source` argument depends on the core schema generation pattern. In the case of [`Annotated`][typing.Annotated], the `source` will be the type being annotated. When [defining a custom type](../concepts/types.md#as-a-method-on-a-custom-type), the `source` will be the actual class where `__get_pydantic_core_schema__` is defined. ## Model validation and serialization While model definition was scoped to the *class* level (i.e. when defining your model), model validation and serialization happens at the *instance* level. Both these concepts are handled in `pydantic-core` (providing a 5 to 20 performance increase compared to Pydantic V1), by using the previously built core schema. `pydantic-core` exposes a [`SchemaValidator`][pydantic_core.SchemaValidator] and [`SchemaSerializer`][pydantic_core.SchemaSerializer] class to perform these tasks: ```python from pydantic import BaseModel class Model(BaseModel): foo: int model = Model.model_validate({'foo': 1}) # (1)! dumped = model.model_dump() # (2)! ``` 1. The provided data is sent to `pydantic-core` by using the [`SchemaValidator.validate_python`][pydantic_core.SchemaValidator.validate_python] method. `pydantic-core` will validate (following the core schema of the model) the data and populate the model's `__dict__` attribute. 2. The `model` instance is sent to `pydantic-core` by using the [`SchemaSerializer.to_python`][pydantic_core.SchemaSerializer.to_python] method. `pydantic-core` will read the instance's `__dict__` attribute and built the appropriate result (again, following the core schema of the model). pydantic-pydantic-ba0aa01/docs/internals/resolving_annotations.md000066400000000000000000000251011517143232300255030ustar00rootroot00000000000000!!! note This section is part of the *internals* documentation, and is partly targeted to contributors. Pydantic heavily relies on [type hints][type hint] at runtime to build schemas for validation, serialization, etc. While type hints were primarily introduced for static type checkers (such as [Mypy] or [Pyright]), they are accessible (and sometimes evaluated) at runtime. This means that the following would fail at runtime, because `Node` has yet to be defined in the current module: ```python {test="skip" lint="skip"} class Node: """Binary tree node.""" # NameError: name 'Node' is not defined: def __init__(self, l: Node, r: Node) -> None: self.left = l self.right = r ``` To circumvent this issue, forward references can be used (by wrapping the annotation in quotes). In Python 3.7, [PEP 563] introduced the concept of *postponed evaluation of annotations*, meaning with the `from __future__ import annotations` [future statement], type hints are stringified by default: ```python {requires="3.12" lint="skip"} from __future__ import annotations from pydantic import BaseModel class Foo(BaseModel): f: MyType # Given the future import above, this is equivalent to: # f: 'MyType' type MyType = int print(Foo.__annotations__) #> {'f': 'MyType'} ``` ## The challenges of runtime evaluation Static type checkers make use of the AST to analyze the defined annotations. Regarding the previous example, this has the benefit of being able to understand what `MyType` refers to when analyzing the class definition of `Foo`, even if `MyType` isn't yet defined at runtime. However, for runtime tools such as Pydantic, it is more challenging to correctly resolve these forward annotations. The Python standard library provides some tools to do so ([`typing.get_type_hints()`][typing.get_type_hints], [`inspect.get_annotations()`][inspect.get_annotations]), but they come with some limitations. Thus, they are being re-implemented in Pydantic with improved support for edge cases. As Pydantic as grown, it's adapted to support many edge cases requiring irregular patterns for annotation evaluation. Some of these use cases aren't necessarily sound from a static type checking perspective. In v2.10, the internal logic was refactored in an attempt to simplify and standardize annotation evaluation. Admittedly, backwards compatibility posed some challenges, and there is still some noticeable scar tissue in the codebase because of this.There's a hope that [PEP 649] (introduced in Python 3.14) will greatly simplify the process, especially when it comes to dealing with locals of a function. To evaluate forward references, Pydantic roughly follows the same logic as described in the documentation of the [`typing.get_type_hints()`][typing.get_type_hints] function. That is, the built-in [`eval()`][eval] function is used by passing the forward reference, a global, and a local namespace. The namespace fetching logic is defined in the sections below. ## Resolving annotations at class definition The following example will be used as a reference throughout this section: ```python {test="skip" lint="skip"} # module1.py: type MyType = int class Base: f1: 'MyType' # module2.py: from pydantic import BaseModel from module1 import Base type MyType = str def inner() -> None: type InnerType = bool class Model(BaseModel, Base): type LocalType = bytes f2: 'MyType' f3: 'InnerType' f4: 'LocalType' f5: 'UnknownType' type InnerType2 = complex ``` When the `Model` class is being built, different [namespaces][namespace] are at play. For each base class of the `Model`'s [MRO][method resolution order] (in reverse order — that is, starting with `Base`), the following logic is applied: 1. Fetch the `__annotations__` key from the current base class' `__dict__`, if present. For `Base`, this will be `{'f1': 'MyType'}`. 2. Iterate over the `__annotations__` items and try to evaluate the annotation [^1] using a custom wrapper around the built-in [`eval()`][eval] function. This function takes two `globals` and `locals` arguments: * The current module's `__dict__` is naturally used as `globals`. For `Base`, this will be `sys.modules['module1'].__dict__`. * For the `locals` argument, Pydantic will try to resolve symbols in the following namespaces, sorted by highest priority: * A namespace created on the fly, containing the current class name (`{cls.__name__: cls}`). This is done in order to support recursive references. * The locals of the current class (i.e. `cls.__dict__`). For `Model`, this will include `LocalType`. * The parent namespace of the class, if different from the globals described above. This is the [locals][frame.f_locals] of the frame where the class is being defined. For `Base`, because the class is being defined in the module directly, this namespace won't be used as it will result in the globals being used again. For `Model`, the parent namespace is the locals of the frame of `inner()`. 3. If the annotation failed to evaluate, it is kept as is, so that the model can be rebuilt at a later stage. This will be the case for `f5`. The following table lists the resolved type annotations for every field, once the `Model` class has been created: | Field name | Resolved annotation | |------------|---------------------| | `f1` | [`int`][] | | `f2` | [`str`][] | | `f3` | [`bool`][] | | `f4` | [`bytes`][] | | `f5` | `'UnknownType'` | ### Limitations and backwards compatibility concerns While the namespace fetching logic is trying to be as accurate as possible, we still face some limitations:
* The locals of the current class (`cls.__dict__`) may include irrelevant entries, most of them being dunder attributes. This means that the following annotation: `f: '__doc__'` will successfully (and unexpectedly) be resolved. * When the `Model` class is being created inside a function, we keep a copy of the [locals][frame.f_locals] of the frame. This copy only includes the symbols defined in the locals when `Model` is being defined, meaning `InnerType2` won't be included (and will **not be** if doing a model rebuild at a later point!). * To avoid memory leaks, we use [weak references][weakref] to the locals of the function, meaning some forward references might not resolve outside the function (1). * Locals of the function are only taken into account for Pydantic models, but this pattern does not apply to dataclasses, typed dictionaries or named tuples.
1. Here is an example: ```python {test="skip" lint="skip"} def func(): A = int class Model(BaseModel): f: 'A | Forward' return Model Model = func() Model.model_rebuild(_types_namespace={'Forward': str}) # pydantic.errors.PydanticUndefinedAnnotation: name 'A' is not defined ``` For backwards compatibility reasons, and to be able to support valid use cases without having to rebuild models, the namespace logic described above is a bit different when it comes to core schema generation. Taking the following example: {#backwards-compatibility-logic} ```python from dataclasses import dataclass from pydantic import BaseModel @dataclass class Foo: a: 'Bar | None' = None class Bar(BaseModel): b: Foo ``` Once the fields for `Bar` have been collected (meaning annotations resolved), the `GenerateSchema` class converts every field into a core schema. When it encounters another class-like field type (such as a dataclass), it will try to evaluate annotations, following roughly the same logic as [described above](#resolving-annotations-at-class-definition). However, to evaluate the `'Bar | None'` annotation, `Bar` needs to be present in the globals or locals, which is normally *not* the case: `Bar` is being created, so it is not "assigned" to the current module's `__dict__` at that point. To avoid having to call [`model_rebuild()`][pydantic.BaseModel.model_rebuild] on `Bar`, both the parent namespace (if `Bar` was to be defined inside a function, and [the namespace provided during a model rebuild](#model-rebuild-semantics)) and the `{Bar.__name__: Bar}` namespace are included in the locals during annotations evaluation of `Foo` (with the lowest priority) (1). { .annotate } 1. This backwards compatibility logic can introduce some inconsistencies, such as the following: ```python {lint="skip"} from dataclasses import dataclass from pydantic import BaseModel @dataclass class Foo: # `a` and `b` shouldn't resolve: a: 'Model' b: 'Inner' def func(): Inner = int class Model(BaseModel): foo: Foo Model.__pydantic_complete__ #> True, should be False. ``` ## Resolving annotations when rebuilding a model When a forward reference fails to evaluate, Pydantic will silently fail and stop the core schema generation process. This can be seen by inspecting the `__pydantic_core_schema__` of a model class: ```python {lint="skip"} from pydantic import BaseModel class Foo(BaseModel): f: 'MyType' Foo.__pydantic_core_schema__ #> ``` If you then properly define `MyType`, you can rebuild the model: ```python {test="skip" lint="skip"} type MyType = int Foo.model_rebuild() Foo.__pydantic_core_schema__ #> {'type': 'model', 'schema': {...}, ...} ``` The [`model_rebuild()`][pydantic.BaseModel.model_rebuild] method uses a *rebuild namespace*, with the following semantics: {#model-rebuild-semantics} * If an explicit `_types_namespace` argument is provided, it is used as the rebuild namespace. * If no namespace is provided, the namespace where the method is called will be used as the rebuild namespace. This *rebuild namespace* will be merged with the model's parent namespace (if it was defined in a function) and used as is (see the [backwards compatibility logic](#backwards-compatibility-logic) described above). [Mypy]: https://www.mypy-lang.org/ [Pyright]: https://github.com/microsoft/pyright/ [PEP 563]: https://peps.python.org/pep-0563/ [PEP 649]: https://peps.python.org/pep-0649/ [future statement]: https://docs.python.org/3/reference/simple_stmts.html#future [^1]: This is done unconditionally, as forward annotations can be only present *as part* of a type hint (e.g. `Optional['int']`), as dictated by the [typing specification](https://typing.readthedocs.io/en/latest/spec/annotations.html#string-annotations). pydantic-pydantic-ba0aa01/docs/logo-white.svg000066400000000000000000000015551517143232300213430ustar00rootroot00000000000000 pydantic-pydantic-ba0aa01/docs/logos/000077500000000000000000000000001517143232300176615ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/docs/logos/adobe_logo.png000066400000000000000000000123331517143232300224630ustar00rootroot00000000000000PNG  IHDRæ$PLTEC6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6}0tRNS ( e_I"4ٍqX>S{k.vN9CQIDATxYN[aᎍ8aǪ_[C=tk"k-kwErZfB9h+iߊ徭mK9x,R@;\2i'eWn%c衕)լ, 98/& ๠/:n!_Et, 8x/. -" md, md*6 _WN78)< `?*ۚ* @6[ A@{)Q%Djp]AMiMxnM?Kd54( ` LD%R XAG$p<v\96cP @T=PXsjǠN7}RdAŃ3cP @tE3!=NQEV ڦ ^t6̜!$1 f,AmaPA(cv p)a@<àP0 4 j:p <,N0h8 j90(4àM6  #> L0 )CX؇AmxA%+@ j70o[$v7o; AI ͜ Gm2NŁ#@6 `gaFDa.E#@0 @ Ui 6@H5 $  ACtaPA!@6 `;iO$ Ad ^b7A RA] F@a> m{m 3l_]} [ iڒNaPA Ԟ0 Z dK $&@h-0hA ]tcՊ\n{ u itmMTR aP jO}% jK׆# jO}% jKKA Ԛ. FA -Ttm3S1y؝0(z b # jE@=sȉ "$ z2L, H"% SJA ߣCJ4J.TF  a=ԡJH! 8SAP²A 0wX~2@i?~ޫ @ gerf@ p7&*_`0e*{(/ߧzV{ ?b|.-|؎{ĿZ6PP ?'Ԧj^J3PM @ ~fj]J4X<x @YN{ԇӱ199v8T=,{SZX @ ހߨk(akrlZAr%qOu8 +T// S,% H>T @ pL @ _R;xg}[U+eq08|J||ƑõkUa+ d.QP <<=W@ <^Vܩ S(LATȱt9>p@-XS`$H0o=)Fd/|ٰ¡3_rLhG#SZ5q~ "f!"Hӌ16ĭ62G~b"HR:"z%4)p8mx rtIN)@$~{' D48Jjj< DIlhlVbL%+o8qVQA?*GI't@:$Y|o1nǩO1L_0Cv@u)J@$rs` Ws,mI^`WV 8]N <@$Sa8D?VS[ ʙ}Ρ%Q#iDۜW vW]0Zx  |e|ݐ@$Xo;TVII r"qI }.wj* GV~@_^,1|Rt$(=ic`%ؑ@|\p>|R/'J0U 5DAYM\ǫ+&XE`%8@ch!v^~CVʱGUY)=%4$f**OW#Fqˋ;JkQ#4dy"+AEθ4uzCD|64=D+IJ +OC2 4nFea*6_8Dh ɭ7$W ^(F\M`%8q4~ 7 @H6J p+끈*R8d=$g- ǍHzfC ?5 e z͍yH뀈`7#+k5@@lZx>>zbIO$Yc7 ',Waࠝ:?܌J?d޲^'2X ܓ2*3 z1O?y:I]{nh^%X|`2` z˟G|fKNh<):f 5apnD@FwW>ШOXKHoYCj jRٸ3` UX*jw3S݉RQCD,d(]z (K2{RZ!>Jz #]Q i(l#mXjio@'E]MQS0v$]KqAXZ+  #M eQ ޸B5(8E_̓k  zc Dž(d"³ߐT6H6k(`Fv |)혉0 x0QZ7"51!U  C~ );p9[{00t\nF>)zbFNb+ YPlZ)]򆀂%HCT.`Ҷ )ּk!-wSf+NC%7 xĭ K`+AB֑;)B2JQAo"9V6ꎻ(@WP l(\Cb)\?'AAK#N BB=q;.o*-~ɱbԭDi( [ʮIHWpsRV־NnņJOC@nEHvpRuIJvń~6=!bqń^ `ȟg3x!A%B myCnӹm:)zEiƭ 2D̤D{q[XP+Ak^@l_$'r0hJ`y" [5?sIsRt9NuHf91\O ւa۶3SZ1\z&I-?̆_JOhA dbQG~LFtw?&d#_%GD"IW t0h/̓GT'E~H<۩N{l,t'E~@eg⽭LC2۾'S*ϡyN^V9~U+ (Z`ЊJ0I}!\ Љg?D[b%vC2M'&*Ӯy7+Q}+IѱlufۙNXT_x&!o5V ^P*\{*m74UiN^!RuJv[z Z̾gD D۱L'E?{F#*uhenD'E8jt{-I;Mow ڷٳ!~+!LsRteo=_!0EARJEIjWw$EUMN!5trgN](+5G}Q62%F!Gl77z4IENDB`pydantic-pydantic-ba0aa01/docs/logos/amazon_logo.png000066400000000000000000000106161517143232300227000ustar00rootroot00000000000000PNG  IHDR/#PLTE#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>#/>V_tRNS>ya/'JZqP5j*B$:ȳ e}傇WSG 32n^OzMӹf:Դ+tIW&" Bw{IDATx`@TUUUUUUUUUUUUUUUUUUUUUUUUUUUUUعT0 ÿ⬨<[q*7++3Wt_ MRJ^}zzzzzzzzzzRd/>eDpۆLz:3ЇF<)Ԑ"Hf|hmd[t ^6^Պ1p_]/{ꓝ}?_mt9Yys@ O'0z2.\ZC X/rj-30܍ ZS3iPW7FxîKv~oܦx̙oU'XT&%*Ud+˙gkʷm͢JdLjB'yҴXfS̄vdABCY rV~Xfޥ{Y Ĕl_YI,9s >=_HȮf-{czb# <$a~m\Cg >zyK3gUхA)|Hº _XO+Í(f)WB+(*Kyѳc/Eb538r#+9|4X>bCqk]`%QK逢 ^#q@ʂi&HL][+ )V(FslutΟ5ӚPm5و\C͒Eu*:߷b]`g'FuzUYWGPl <١?\ˎ:kgI,J+c6ťAo7I󿎾LMm AE5uOs~.١ll&FtfmCm6 vJKEA誰Ug=EC#ʽ,KS q$[c3͵CeςPT!ޜtlmSJ]5gK&c蠩atͫG}8-_:#p[0TC=7x%x|7Q0 -'|J,~7(?'΢uUyf=~dBf+T\v0SFO/-5]N (Wѫ W >|W pM4bK7Æ2z)^amI4E?]^Yo@>;#&^T1`EGk.Z $Hҍ5⠊@obA9z dЍVW,z˹ *݀;<#݋:&W, VdGtԑ>Vэ33yr#FȟAIC :)Nܕ`Nj[۳f;pXU`to.^XWuVuE1hrɉު z 'wm"ӏeZc!jspFDoE}?N7 TyyL׷§ !i"GzaGcǣ68zE,ݙ}/9>UF/x;gGhui]tC~1+E+03رN"B_iEWB#f Gh?X֊砗?>9I J$c~0Q8{MzDknWQV{pv孢xH2ɧ{GXCEuIAnv*[W,p=](1ǔDǼYoIN K0s$Z=-[MPKfg@=1Vz3#k;U= U8^w F'jFoB |t>@=^|h5z _Pe4-0Rc{+%?EcYar5>-mh| zC]WҼ.堖Ɖ)e!,YcMl YԎ< +S7Wc`/\Z=A; EM/knvwL2'CÛ[ɏnwh/ѣhˬT/=+ ]eR_N8hHo47U=c#r[JH2ܰ. L]H q́zQn)(zKc"˾gA]Tt^3}XxxS* E#>s!zayeAlm[X VLzn!7,7u ç̃HP!\1 T]p"Z%`a0d9~V[p+KΨS1&8&GB*S򨶬 M֖Ls+U/=%5$}ˬG.V2Д.>WژNhw[TYnF:,_t)u+ݑo7tt]Y HP2!9wO1+RMc !eJPf`$g^h_>Էhkw|g tUO\NYV%3jk1ÌQd.nl@)* H@YHi8L_!G<p HPJ_YZ}2QUgu`|w.&P|I\G,N42w'iC뙅Q$%187*{-]Op9.Zt9Ym-. &B< X j(kVCZ`[?|9ǟv )___؊fՕrqeIm qB*z`Ff0F ~׷Jz2Us-\>JaZVAYɕ⇗rrp|"~R_y_c&8xЉ]4Mu>_u00}f{1ƽi @/:B:ŌgBy$̴- kx݃Rr0ygr]azEC:A*t-ВBu}!c; ^1M1ZopHk)"7b r)x%[;|`\k XċN}CWA16Y.bÕ5Ƒ>JJڗ8'ؒi)Q6(pīp;d d@M>dU + dP򒵋2vI(Vm] @^exG\m%Zla+Eb'7vx%c*gR4G'"t×aRf]B&&h4Ď6bXKhQKlSDfCV{|BH>1u}ˌhHO^amj6A񘦗 ]s:D2 Th#r+C|3K6A`hPCiH L~7ط( mJibh417},qk×QXO!ڢw9wy:<]Bh,,zlC<맲f|k,I:7/@TUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU=8o >47=\IENDB`pydantic-pydantic-ba0aa01/docs/logos/anthropic_logo.png000066400000000000000000000402141517143232300233770ustar00rootroot00000000000000PNG  IHDRaPLTE̛z ͜x ʜz""%!ȝyϛu͜{˚v͛v"ϝ{!#ɝ}̞|КxК{˚xkW!!!њtО}ʙx!%$ϙrȜ+%͘r!!"'ȟě̜~͜tʜ!$ ǟȚzϙu""͚|Ǜ|!"!"ʛ}3&њv&ŜИ~ƙx$ɞu)ɗv#$$$ #$"əwʜxќypјz+Þ"ŝ(!˞ƠtǖuЛsƟyќv7%-Ġ͟~ԞxΘx-#!ӘrgL9!͚(#)ƞ 0zʕo$#$ҡ&Ԗ{:,!əs%$* Ȝȗ~ʝum\ßɡԜuʛ$%ӟ|ˠϙϡϖn")C/ ™{ќtיmǣ<) ×xwn% 7"tyd%)΢ŸragVD3&V>-O8& {ėsΜpoVD1#Ԛq]H7&#!1 ƞ~{ƕr˚ס{әzәvt`fSE`M@VF;!Ӥ٘tqiO?M;,H6+i&"waRw\J+('Ҝӗwv ҕkp\L;3*ǣnWWC1s}lcMwiJ=4ͣڞwD)̞y#$hYML1sS;mlxh^~ʛk{_rU}nb؜\=oD&^ :=GIDATxfޣ^.cw1{`" 7" fDA`b)W=,MMOieYY)~~9s\ع~;AAAAAAAAAAAAA?h|ȷ%#3Q2ɓGQz[Wu8H `CkII~;D:* eQK@nNCoިe(?rx $JO^} `P|΅hTvsճrsj{QjC0~&$ AM 4%%6jeGnmK0Y 17z"S]plTdv;Sa.^l0U9A )2ZUsQa``f\;O'4`DBYnw (_ :igSSӤ5.j `0I>on~X t3&C38 7uAaSG[αp/䓑U[2ڹTpuErbLz6zvzx;,,p Hm.=UUP T9\E">_&X(ŖWZJF y5K0=Î\]|YBW7ZJC'ztƞP>\k wq8\oE]>u0pR~05"PClh PzZ@稪U{Cb7pu&,ftWF B(||Ҟ1K#rq=EZrjh2ݒ49ʇ#D& VF#pq!H*t^rMipGZoKG'׉-6sp\.{5..dG|#V!|IZeiô*AEaiTvxn49 ^b {0!GaApϕ\M(u9D._8(; r=4vJ9<)BTHa+1Q/ZK'$77-yg.YH**tOi)86Ѣ>¢^mxkۚ5kER Jb/V!;!DAs|ݕ^OJp>m=(Qojf־GJ~wQi|<{̷)A7f5GG"s> yÉJoX )=s֛;WQ{4Lt 'ߎiqX$/Е٬7A3-OdA au>9>BA]Uwﳒg: i5KG*ª "ar=HWD8B!fxk~颽(Ȑ w}5Muc |ܘR>`ܦ+`jt/8cI"n3G ;5|ULLtq@̪ ''pvQ@A%>nnn g$I+u,p`"m0y݋ Leb'U120eŁ\|bW7%οV$ `;[IHRۃ "#H^OEt%I mceS'Qo~L X&,'1L3)(xCABݓٓ|1]DWɈ($a$U/^!CsK06%ĄN(H {01ͫ0zXawO>6CA6]HH@O Hq#uCAߧcS& 8 LJmLc˦Yc !E*  V vA Iuu S= /;ՒF 29AwA/ɳտùaO(5DfG'4FzR .#gl|!P8O))_+^ȓ)Ԝy|0Ef(ATjճd8HyijACLxqLiln/0ނʘ׹w]ZL&S2joJs> blX{TD /qʊW48vl, cnVO4a 3WxkApɰ ҞYs^knU ]-,+k2!KOj3X("c֩. D:J 2 ͙zs6t̯ѥKQgnb`eL-jS`8",lYG"aOzչ %2 L][Oi #0 9eC]/ O\ ~w[|̨AkA,?yMP `( S3]ֵ╊t Ձ p 'ń۽|8=;98f4uU u15D#{=ۦ xr.9Ϙpns6T&WmfKRw|s6Nw;\ 1Ę.IδjU'Z2n[1Q➼'^[g*: AU˒pv\H$|> 3/ۄ$Q'*Da˳\u'Âxmkh160%5~{UKHlFVFDT$/' 0a|?$ԻRqv &"hZOwGdH|n*="J>Ln!#-u=3Dz TSW{y/ $$IؓA!&>""kEP *"ᾎmjݵˌ[]i;m}h'/gGߩ3紇q1-s4 (wf- K$Yh2 AA6(Laғ:0-K%C02A? vR{630ĵw bs\ $}%Ίc7pj~䜚@t$>!VǤss67yb!H=.Lύ"Fp(4t64=m֩*6 KUE EK5asW 3),I!ڵ#碱!UG^{Y0ڠe+i (|pE9W["@!ZU=[3ɔaq6*;`u x-m娋Us9: 5D㕑K$9G镩9Gy,yNK>@ uNBʭjtāW|冥<{+:!R^~V`aK73!DW49єi$NHkydՂdiٛm%+VQoa0;Q#o}S4)<ˍ,amhmgJ9ða.{g{KѠ8-@ B,q>O&urNFʩvԝ#V:!s5"m)s0qD)$ur񻚻pkRX5_ST. "Q+O)$xƼ?U0{EH!(b߿vɩ+'+EL!YKՃ{P^ *foUhm)]NLoWɂ@!m>..U[u(ӤtgMцwka^-rDŗCjSB2FAWa&Un(uwD Yx jX@2W5`(M]v\uoH~p;:BD6m?|TÂ]rJCЍ.m3-0os,3hd-3? )ړ눨$+BmZȕ!o>>{ aEҪ),ccBY|j܍i':p Ѝ^²Kķ|!D8 a B0+`Y!oth4E#D:eYkw1ʶ5„\p.E붬H ķ)B-;yIf' mR{tgޘPȼyzt =ws~ֲmxӮ:OJ AxCLÉ֊2X$20!88BNAXW,#Ԟt֨M 7ԡ{kPyq0qYu9UI0l(e`ɼJǾW@ x[qC F80e:.DOolF=B9kk4-Gw}aDGW/WԯSyP?cOks@|$HBRbķ+̗Ԋg'_O^,Og6bnE4o.PȯaT, ,`bJ"B=|IʾOh@P!T%&v.'?$8=O)yV̼P5b" ^z@!'' *a!dG3c䐷Ѽ>@h7ٯF,[Qƪmرݮ0鲳=ĭzpOoWNDGFHݑ6"RL!P#c,WZA޻;3ۏŸvZX2s'(jL~ 2xO{Gzo'K<`V?8$+Ji!i񔓋"W02y7zҮ=6%a76B$=>v2(fBPBBf>Oہ ;T\Ǥ=+y X^w&:dSɊҤr:!:=VW.9>zzˊS93d(P [#ƎB[ 3zL*bItBc5KG*`)'y!1c!1EJnwE]mO$^!L`^gO)$k;$`Ń%n]bK٘1DSEQnE-j#\@L_U̪OV/BLl}D*!N'g*KFct\Bˮԝfv[pK%Ҫdu=_(eg=)d4|!H8jGK %"B%IS6N) 2_'e~~J!vL !`$hwB}!Kվ>5vT{nbo8;e}"E(lN-R/=3sX]`>R$sjVTNjsG#Q0-g̘1>9YϙjB!B&FU%%%\ ! u <p^ ssy_ǮA#"ZяT-X_݉\G ],Ay˞C'9Hf :qI!${+N|؅šx\/5˘qr\i04f$f[dv/F/{5x4B~=KW|B~W(t.kZHLB 2@glhI,Pi\BH# 6,XhbC /ƚM~Ŷߨv= BnV?v"vZIӣBx7U"el3d)ҖpJ`ehe6-95UFB zZ8|1|IX<**~_5.ۏvEkqu .sN͚ća#)BBrv@H#xϵQX<4#p<h[7kQjb1l&7b#í} )Ί݃\Z&!z=Z}pfʲ=eIpK#EMg_-HX}NJn`7q0@#aRy݆ąy pb_Nl(^+tW~Sׁ[9mChl0Z!x8kӾ9fzxLPnp_2UHo?RnKw..8+8B"Ѳjj9'^uu?8K<\ IYXrNo P($%l*SGxL#ӫ+0J ;U VG{u <ȼIs#uJA 6`a[fEVԎ!QҰ"`;e81 ***~u%8SOZPI2%AX ~3 IڷN9,ؖR3%mcAe;z1N.Ruz/KY/ճ=jիE{?Õm+ŀ^2Dl@X]ZI 1v̈́N~bہ"b8<Π+M3,bUjΜmw\ԩR=Ft8p4ŮWX hqxng.W6b*ynv1Qij !Zl+ 9^`afѻ75 1-c}wY w|SË!leyN 7 17k Of=:^XlVglK#OZʺnÖ!>a13;-a,b"K#xOǨ9o W|ļuy}BZ3E-' Vl6BveYV`p>}ubK,rR'$2o$Z}jԗ"t@gzl"2,p(TNt{zRs}3gV&C!'ۓcˑX"qpbm O1bر#`ֈNBdUoF A׌de{TwȀ Oi&p<{Fy' ] Y!.g6ďX 61cJl?ppyRUaBꄄyy gȎYhW= BBٺںrf$0w-67Y![(`au \ ,#+=mLh&JtM*[?G:ȸ>O=fX0c8"<1:!g^ρ'l|<<," ),x*0s#n;3fzǒ *\`\i]R4q(<.Nz(0GH#0)ߕ>;~b㽟#l焰,^h]X8pˑF~g/CBB~δ޻PQ@+DFG;iphw'PJGugyBxL 1lzTVxg¼'b~D +wUO:;I}/;zKU ?;o՛ ǙPI-#mJ4 URD>ۊ#aWCО9F;w"n8nٻ`Oo`?O:sD}F /Id:–Q???[< ,e4šridh9< 6LO A겲 gzgHJYX/A0]oJ>b{L<"i0 LA^xf 6[z2 `z0G,瞈?*c-] ߂Bq_Y 9! T`\\F #~hcZѫdЁ @ AڤXl΁m^!e32]x؁"Vx.KLy2N~quő=eLjh25| {w|A&lYv(& $9l`wGl`6j)PI!.5(M}"!rmuxkq6LOE^0 O `e}s80e.Qc Wȭc/ zVn(VRGZP=7<>ڷ: FQ>:WX栿;RlorQK fg>#5l;eB`;0ۮz5Aa'\j)2V\Q14B|Cn~mCLELǾ7̿8:,!rEfeEHziYTmQ1ӓr&! ߑeaCtAs)P.9ܷe8oc\.!퐵֍WHgo3Xh4/RE{l˺x:hl**=ͼuO(vZ;u g)KAF_k;u' 3q #R(kyoN !AQhC!iN C"e[]GzGr)B <T5WExė&OY!!t\ET!(Q~(Y{A8zimq9 l%J'dyd&K̞8oerưG}N`D2bfz+(,OɏH"ܖeMT Cɼ\X|SR#cS!' HRayF " BJ֭n*D%RH.5Ya0~4B |>ޏNڎi:ӯ'Of0=!g^6/QW gc\2zB) i!Lժe/pE >Nfyi!l- va"}FJFJ.a ItBlH#XDd?l8 TPZj"JA+8o=+--{poEi٨:bMgjfe-  "(R Ufb4._eq| W2(Jk\'?!bPȱʂyC \8U:|UWzvV%n!F< I/yоYm8iJ)bfAu" aB8ukN|ELW-O,fES T)+69n'_[BX;g^ƿz!2Q4=5le@ķ qi8{ˠȿ1jB W1[ (B-"޺d?ψ7%w=̿ZKҗ]*EjXe9!ƭ 2 7$tyӸ%9)eԧh[qxk{!D)!L L/vޱj5җ%sw?|Huy>GB2k$+ciib#Ul93N{*V>Zࢌ݈LT+0k /y(MmzM)wPA! h<6WޕY)x[lq L⽨E*x%%Opϥ%le% & D0"kaʟ4|P+m*'*@A2K&=!8<` S5"go%3`u0W8$K(U2Y A]"loe3 digzjӠ\<ɿ"Q L U\ %PA[Xa#,K>HcMY i/;Vpx ~*H[kz*7_eA8 A]?7=D2h9pm>I7lc>=ab֑zJH e&z*I+ ڳ˿ҦmZ 2{D}#)Ӥu]pyZdL0bE|a_6~{"xٙӭ[ᢟ:JD_k;Z i069C!<BCaxم`b!:crPK;ẀBuW D/;ny}}c#!h陇; l'bN{.)5%D+G2&tJytB4C iԩSnooeDCrRk*|>/;d+kb3B 1\N m <32ֆRT{axKI$΂so(;'{,-Č]UlүNs#-%l5J N'j* s\r!4"l#\⡐(طa9!HVC[jUG5l#/9h_'TPZ(4i.aX%333rGy)k?`Ae#:_ MUkT 6HPӷ/͋)'Oβ{WGjuvrqQNNGyGU r 'FP1 z#,@q95YSK|#Z=k~ dM9E&F/ .ܟ${+L `M}{#>y9xّyϵT'x-yy 6fe+fW$P؂s7"hnlDss?yoq+\Q@#s֊FLyW牼_wD1Z% pbu7Q)!F<`>׆t}rӧ peW8O`R^ w9 j O-:Ǎ ,wܧ;͞c#!s&/#C&bZ66K#~D(yyu"jd_'74蘥,(' 1/;"N.]]LONɹBH!s"TT:>6O.y2!"{wv(2#g64/"(pw6bѧmӧ߀B$ !+cd }kmM܉-?NQ')L ߗ;P|w| ,;4x/k^׼5yk^׼5yk^׼5yk,us!IENDB`pydantic-pydantic-ba0aa01/docs/logos/apple_logo.png000066400000000000000000000142011517143232300225060ustar00rootroot00000000000000PNG  IHDRV " PLTEM'A*tRNS ;.(as$4{jCQJXσ'IDATxkr0aIC1Kp6tIX}pfd} D6Jb^Bam>ù*N7҉@$cWcdECFN$MxNl 0$k/TK "mV&3 9^ǹ$҉,KOMZ>ʭR*'Nf׉$҉?I:lJ_bVznN\"~/u1}v-Y f0UZ7׊xn/Nw۱W$uD_zmnFf&oOuZEERr'[ru3Jz//jʝnO*~0hSʓ3*Gz %g8uR繼s)G-?%}L \c›˧p×x1W xxbF78gW>;_APf{Vt'HwNh#,q7lQ1l,`n=m0q %! 0Ќ_m@{豰$+ZyFbAɓ$vcs2QX\4|[M.c~%iъW8؟owCyx,ys_Xb~FOKO+Dtń+QORΰ= f,*ё3v Ow0`IY~1ZtIfN+:5vX=:v _Q#JNuӢτaudVt̩&.CDlDL^h[#*&)=w oR4,NV4 ٯE- K' /s`Vԉ:aQ_#oաAm% 0FI`%+>7"szD$YKXsʢxmLEV FV흄k*9$z&/EJ%B[dd{es}̊0o:~UPZ5㌙/hÎw߈rCAա&ir' I3bÆ4 jP93%'͆rWuxP+| YVcHx3?,܆A-:aZb_9|T<A͎kUsO זT/qwڥt\_(aFhƒ݌wJtwu4pj▦r.WumvCo]Ow (b#r9wm0@Ejg,?`Gڦ#͔-( A)X5,}Pihh nΩ[Vj?.UU, t ifᗥs2+6쐋q99u.L6i_ql۶ o".7.&K+qOv%p24'6g~[Fv܏Aid[Kj5Ŵr_4uTBm8T m 2viq&>G%xv|1qj<(ĒBMJU1Ir;mҽftծby^3%2Zn\w?@n#q3%%3jE&O;VVS$n-nߗy]m=x+lyVo@ZU\-D|.KwH#ZMՓ*/akxۓ\IM|++gm&;2i'џ_Qܚ;}o?/j燱..qu ɥ_F׮AސL?yGhE{F? 5{1w,z|ʴg4[i ´=5}Jf2;wj>O|sM=p!&Q~ŷH?N^mj>[c$6{ɸ!s-/>#jW1GЧ|oS4 B^G0M5>ޢt/sƖse΍o\](-x ' `zsƲBxNRpNɄ#$IXS:'9|ƙ;,oWZI$5ƑMx"l@YlPd]YH6Dʈ|I):6$HK l'gS^\߄TYdTD[7`~+%b'`ޑ/gDq#뽓Sffrg9)RWK(pY(rHI\PT1وSŇkgߦpduаaw*_Ww'yNd0bSpj%)`HŔ giMEReRP>j}_8X{R&ɗ"=Ez &(EvkyUjelJRA)IhX I^Xz͕@kr55T{՝IYޚkhU0LoS/{ӳv(oֲG*c\.[4M|%U$:s4D)֓&`NљKtf24Xx(ω\:2Eg.):sNљCM/J-ޢ[NљKt\eAtR):w'iAE%Hb8FoI(v0Ϣ.1_4hg0^<{_0c{R)MxVI,&ikLe⼚j6I06 c2tc٘R5YB»Oހ']4Yc@3:`c,.82:$tW,ݨ@BQYea7ܻU]x451"3ɏo\~ڡ>xZI_Tټuj6vg]m@eRQIJhs\#E`F_IT&[GYI~4[aJdpf{ ={x$>B+[cio$rX2%x*rtulĶ}{<IpAyefvs Dm8!hҋ TטFODS=p=gQs* Y|E:iX1,TJx GBu\dr ?ت" }sgd ksҗvKι[m6&f8aUV  ]&:ЫISӦW'{ڬ& $rGrQL=U.}|u&݅#P o#MpTې5C^D0z=㡔n } I jQ B0cGl m`? Fb;U(Gl' Wt!AN%hѡ<} q@S뫩QKta#N= %a)"y}ajs8M.afo%,Aq}DZigE* ǕYCHFJPꆹ4m~lBюH+i%N(@%2U$j%UB\F*~E2i2aDcIzR%|$$2i6zv`&[Ol:BǬBl:5 hB#Iz}v:7 '#zj:08q:49a=dt!hL/ĜN8jPʏb9 YԨ$XXdaybq$B'!Еi7lϫX/wNb;$:>)k~\9NYkئV5%Tra\h0LO.pD%8ǑaH.\G5@.chӰC]^mzuQ(V{6'Kx6ձv+U" 'T,(QA+mӔ{."l9iHz! c ̉vB*wT^*6=eiP zDuJ˙hhjE?9i٤SxmIurXqsg 鍩-%-sqo ~8)D{9``HlyR^(v,C9c?g;uŒ&rw{/Lm,isOZ#HmqGyb;bIƏŘ^uf,W%V`Ccd6ymyC>+#ӗckU].fXRw!ڄq>eGRKf:5ކ+qWci'i5¿peT8N>t>mN770=izfmc+Piן]|gˌ]@@ Wq2<IENDB`pydantic-pydantic-ba0aa01/docs/logos/asml_logo.png000066400000000000000000000151671517143232300223550ustar00rootroot00000000000000PNG  IHDR/PLTE#"#######" !### " "#"" ! # "##"# $#### " !## ! ! ###"!" #""##$##%"#!####" !$#"#"""##  ""$"  ! ""!""#$#"  !"%  $%     $$! $   '  $! #  )""  '  (     & '   $ '    #%,w0w)##"#$$"%$$#""$$%$%!&!))wtRNSSa# `{;d5¯?1yPL%Y/iG,'s8ͫnUJŲvk\B*}oWDڻoN̹i^W71῱O FĹd^G?/+$ȇ|wcSϴZ^s!|<-Uh}FdMkјuBi;ϚzDFwU5gR\rċ;8aMYE@E-L3I2},iߗϹ;;`)H{>y }>e.ؤlG;EsdTqůԛ')xZ/unok ]3@CS;MzC=%*ۂ1VYh= 8v(F j[ j@ʶ,tGNׅ9GqUePƫH{Ɂ 䮇5z#[/2 IuB CqhPŮϔ `<9,*61ˣ7qhRz[*$%o9P8C%h+ٕ'E4Um$zd c!5ݤ0TI߅>BH6 H&HAʼHb "fC5%h;Df(#:yoo'O=b6Go3hL#ymoaL4>SDI!&ؼѿ g R0SQj/YwHJ |9M8]GK0q5<:uѿ`$A])U5P|>_Fq28a\c[I` ɔgJ0stZ@B&SX<pޥ4L6zfv A,͋g?~pd49iql`%ԛFl=g]s %SIn7#XtFHl0\h%7pX~Bu>L52YէڶT1>#2tQ2rwUv6DV1hC+[w,֕jt3@KyB@K锥O0[H]LZ 7K) ; 6UYʠz Q=ћA\9wBն>*A!R{XHbC(hLX}"c$UˡSގ8$R{YEROd4{ &+F^{̓:U+sɷ)\It@/kGw۬>C [84)z h".9Br4e') ؄ѫ\oj#E`_bw7A*<HnJ(Nm8DJua)hpp@r-Жl1k1 "θlx!58Yy2lH?M38$7.o>pAk1z\!Y 1U?QpX5I%BץG(I*'˅1R8/`ǭՇD7NRi/w8`Arh[t ~۠!ܽaXt'E0#Epbr  (Z=XyFnѲ.Ъ>3q9p?:0dYD /ЪĔ|K86GQ#{]@xV=I@-6{580A fG~&܃`aq0Ȍ=I|z_BB7T/쾙"2L0DPUѻ &A&F",cP(E QH4D6Z3`37¢=O!쭢uʜ#CP͢n: ~ ZbA!@ŞsU__5xKgclIQGia9i?$⍶D߱a]p (-5H6Yt']'"CB-wsY6EV!C]hY*~ s< >G凾(}EqqHQAt&B,DT$Ƙjz<ɓzA wv3_ep x#o~GpWQM4pl?V$p *ZÄQg?4= 7fM} Ϋ K>=d;g>/mDt%ZÉBtfls`iS o=UXnBjW>MƤ Tޥ8UBvWӪ$9YUd|sDoW׋#Q Va-wLt 5KחZ!x9rLtM ôr$]bvSD?F;!ņ/% .U뾮H']G„T^o;* & ?}{uY(]ՄTZ15K[EEƹo8 SnrC-Kw!z;8z5{~FGҾ Z4~2 h693 p%vR; Uʥa𳴢G Va@*J+LÝs|DoG,P`~cOR`v J:2z]@Ҋ/)+~9 cԗ@7{HNpJihrxc2 WU3ilg!}hZ.V{5FfD%tM@*?.E>I<  jn,*' P Ig}Z6Xz6ΧxWCRؓKܞ&y}ʋU["ip'RUaw%$ wɃ7wVq:7 7^PbG!*+ wfwʃ EiKrqK2xʀD(v"&_,V׾͂7ϥ}BGSp~Bn؞7=SĀF~Es`TT φMxauMEfğ]Gg^(*n})zrL$8}@aOBU}`5: لgA7W`X{}"[|AeG?a\Z((SoP'tmFg$ѣR&`D6.([QR egrC\)KIi&zC]5K9P1O&+B9(OS'^,IFMzCPIr. i "g$pL)C߁(XFy)e^p'x!ڀG;H=J$/F+Jv}`@EYpÔL`Y{>\|Zґxj(1Il,mL `}T&HAW9 "R?Ղ0ehUtn<#I*ڒ ADrxkNeet6(5UG*|vʥ9y=iEIp;(5d*OGVݧ&]\XXiiiiiiiiiiiiiiiiiiiiiii@* *0HOcIENDB`pydantic-pydantic-ba0aa01/docs/logos/astrazeneca_logo.png000066400000000000000000000271331517143232300237150ustar00rootroot00000000000000PNG  IHDR/PLTEɝ-*nճsqMK{yQOmkKIgd}|_^;8wc`~ۧ®ǥ-*n86vĚ$41sFCLJGEVSfcurkp濰+< ! +gx<P:u&qS@ *;6 rә5Θ}(ۙv&]Ā0}o:% B\LT&D_bQM9We'jePpB™[9#v`ߙ#3@eg3[}$gLbB$f =|u Hئg󍥜q%9P|8Ccg0]JϙIʗp QHe3)XcD@y聯'ߝINFpm/83fJښwfa,[q&e8 ֢{׾ "Hz3khAܛj'ceN^ӕ_tIfK c2 3I4x+Gpc X!ܼ3Ixƌ{OBbFFIK|xJ>Z˶0P\} = GsĢ#?;]v%ܚqF7BOlGhwb+?RBFDH?u$D_Z x;Tdqp35SBuXegmcU<|Y1&V36$d_K'׏?le"^s"T813{wk>PB ^|fQɻ w/xDƊG([7#u,P@ %/Y"Y2$T֖Y*,{s2e\]"mF|̖r9=s__mj}=ZU;9k=R'Pj&"@ygFQWj@DEefY7{=DB{0֧Q^GC񳵬5ne 5owE=$2nFXQv!{ o[|Tӯf_@gjd0cypm'c=psV!`{>syUM7hU1Jm۫)a+՚7Vy$$G O"P?%(`gwәr=s8dMwJNe}o i9[Gr&5u x,<^EsŵB+am ?r9DWVv>aڙ'+ `;ׯ?]xEĠH4(͚`RMEE 6Q@lذ{v?d^y鄀{+{ ۧ~!{eofyuQAGH7إ3"jmܵ{ 0U hSqF 9'/0)^9ɁG;ΛK1Y1X%?p+q"9Rĉ<_ z)v kza`iF2?Ƚ '&9lo>5.׵m9XuRa/98 G2O؎ͫ;`n7br({`x9P6y  6s[uM|GXKQ=%tD\ kKfiJRΐYkysk,\ ? 8ph;Q87'&=IsR4Y9(O`7m3@F֜$-\.YoH~МF Mf߸ 5DEnR9B/Hdm,ۙc%{vFXm; Iױ`~TvR?D.ΒVuad%{^`E}O{pS_|;g^;ShL0B/(·+>U>m6v۹۾2>]mݒ<&VW?K gOї \ *\wBNڍΥI:^=$ƴ_:xzjڸpe\ 0i)̡ 7z(`0Uy #F( &܋/]~ ;`tz:AoٕyL&8sWTy5ey g1gĒ|ߵ^{ߵAǸ=!uf]ӨK0xhBD̙H?ޝi/]kτ4̪ +9=?:,&5^Ҿ3'Eܣz ]MkIa1,%S TJU^ѳ+EA!ݡiJ%VL'[xgDEe}QlN)BP{ Bʢ[ È ku fYU(J_A0fڦ_()Vt"K'wvOi *KP詞eS;v~nL[P܄r)!L!N2 3.Zˢ 9G l$}%]fwgڭk0E bDO1/E\3Iӱ)6&'Ni- YW빈>8B> 0G_c|0gF\p6|Q4-2E/EgaZr >iݑi_{g|Bqf=~Qw2qW<*z{ky}":ؼGfRT ,.1I7\ʻ&SW_&8'L~Ε:j(2eRGhq*i,Vs9%+hzpƬt#XȮ8ah`vCA9A2c]aRWu/9k+uhCn=^k3Zz&UC`J-4Җ` Dx wi &oM^ ,@#Ȑ /rvR(ƘԞ`Bq}]!)u,Y^*hE+dk¥ Ó8DB@p%,I gV]#u YTX=é 0"UY, Ry1.ҁڅ~ãLGRKTT>T{dT^ÉteWAO;|"6jq㊪C 8!l;w{Q!7V.蹳z8SNT;13fH+:bY:q@ן0|Cc%J63G\`ikE=t3nWh2[)v({qhZe[UT'/8FU`'g6&Z.Cn^<']x'`zMMaFu:*6k/pZGՀ[qc r&\6㣜80^yd}J@bw虒t#Si}<6iJ 杈A)tXmNAhsƨu qb&u"G{>}Ϸk7ڎyUܱ۬_`")i hEmˉVnrF LzWʂ0X1o"A{tBDYʱHǠ D@xr B*mELtZXӢ }o贶jQ&c<َQ1vy] spQ1cA/ʥ p}HGzh*L$]pQhIU[R:8R8GΪD uU@m  Uȩi^po[VJ5=Hlmi)f`*}ǘAư軷B'QPjҵ&#<m]^ݹ mM @$pIǬN]eyB3ԕu,. 2`/`L¬yL[!A[wyq*bI7LoӁsҽOaO<6\b#C&Ǝa6,S[<,ćNDY"CG+96w|hS/dl NL606>ЏvǺ ~s\$> Hwӷd }_2Yv^QEcہvǤږa;ڰ6πK6`4L6sc)r \1mU pw}oޢt6MקV$مOUWvw7(IHۣ9"՚?xm2[6b$( =AOu95￀!Ӈ2akf?0kȀZiG=,NӒ~9Rխr(ҩ&/0E&^? /*ʝFNj&;-bЌHҝ490I҃xiqϧ J4`'}z~_vݜf @Poe89tA~&jAUaяyk} ߖ>46D`5w#o~v(R˅| |- b{{rY_y@E%Gʌt(l8NQ!nιRǧ!k g,c-ĨOOG{pٯ~شyrfԢ`K`UAp"ftT@r:I ᔹ#{Bv{y_^l (a9AvuYttXkp46;rB҇i)(.z^xAƒSp$$xP3!YədZ~$},p1:ȸ>ӗuҁ ߁L*g[K8nn/ٗT9cEÁrEG,7ud&1nĊEL*VB{~7P@lOWY+S{{5?zg߹Qj(GԨr]$Ѫ RWF~ =XQ5.O^d51AC@ۮƨLH]]̻*6_1׫X{$]ࡗIG:Sw$:D(k>{8h.gQCВJ^/s}[T>~D8sINL5s 8eTJpcp8R6},dkewlKbX1tCw$=cס$KR fzfQ5q +)'͏:5Ič~@@W-NK@glo_ h'o ݕSkl' ’<-B&5 n=lvPKp[~9o]w3IG8;Y·Q#;Ȅ#b;RW.ЅhJ3P3Gۦ˪8IϞ@xP* OKz H! is: wϼׁYYة1dy7]Y>3Y g 3m}2BH4ш#0N? R,;| PLӇ^t;Ē^~^8MLK1841ͮ$O tnl~椻^8Z}S~Pw)U)M$:/z'Ր1L\<EzQМJU+gVIw=FAӕ}ҮJ7z&BN'pG}4ﱇc{G?ww g?qa NBI ҉1MOCT$=NϴϲHD;%3uΧ !s>-,4Hl~ztf8*蹫KM*嚊W$-&#.T옑#{>9ꉳz[xMT,œKS:I7Wȼ_ڮv؝fUgM0Iv1Sw30 Xg JҭL5N[ Q)Hj7WW] x(4WX~ܜJp'A7Ө8 ?sh|;Rε]JDC -epUVB _kۣuP*'"qp6WmO|~9nVt:ĔUya7vuv/A+<+ryC@Sz_u wOm5~t^HYN)^1$.:BJEuiCMG J!ɢ 6b[֨u)1iXwhU6Wm)%3p8'7&ح-̉!ݚU^7-S`]fLϔ8d0=U!:o-,jh=4/J~`uDjXRme*h)4۝qK5ũ '{F0Y)Y}S=kǦL`)1I40IOŢ|mSVg1 f܈E B>fueAdž͝PuW+|skҹG/AfRa#8PlVyVCl~w75ciwgy:}n\fWDDpwn*2꛽ B5It݋;w+U*Fp_d׳ 5p|d(lQdeof-HfM@NkVM˦m7G gB?+U#";glŭ @0CAKURpzx$=\!SG +֘ZL[z{ͬ!FkS=MGd/((r=={Y]++S6ST-4p 1cx5qxXVPda?Ѩj{E >z3|D߭9XZS-$q]`V\H ^Y܈" BXB!D׼Qمc C4,?C8 X;{*)k؍'Q H:^%,+ӆ*2CEIջl1ZM{+p"J aJȚ^"ccEA;`8X8,Qk;ƉU!~62u)7:1}NJ \&Nq֟Bұ@FPMEYLv\ $^dЩ69B{^1.ل6Dq|,MZzi51ZҤXZ mBKiA( `={Ԉe)ijH.J,xѭ٘&6Ĥg'۸kA!0gd^fee6#QE,λXy)rcʅIh2gDS,7:7:l! ke*)[u.8,% .$D=O%KbFt`}y A>#O]YB,{B~h/Eld{ix@uP܈DO$ZN&^+ΎGYN51o۝sXq; aN2*AbQ7joNrܬщo\ΞwL5@1?"'Ab.vYΑb:i&{q(˅f}"+'}IA`xvts<8 {mkr,0ZII?|gf&Ũ43n\r7==b];o ֓JF;]f0۽~غϷ_0Uty(H!Yi5Cܓ+K[ZZ Fc F'!V BaK&'^{^1Y `F~K44%f;(/UW1Q0 k#@*k#@*!a37w+IENDB`pydantic-pydantic-ba0aa01/docs/logos/capital_one_logo.png000066400000000000000000001136731517143232300237000ustar00rootroot00000000000000PNG  IHDRߊIDATxy\u=֊XĎMF1H*ad# d#c'gI&q;N&du@Ӟ$q/XeX"vm]{~SVu[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\}aڜ;XOM a0kwg}Ɍ] ̒ NfnHDfeNK.UR"ZT?!'TxO"$'4W 4$WL :0a"{E#+*"/]3]I|gϔd}6*a d rT&0}aWSgURK+0" tttz87V[HWmΈ 03'"x$}=S<|El;1*n?& xCQ@˚_Y_AQVKf?a072' R Q2`$"$@""̆ 4B!hCH|X©Ū*DGi#<.(-;(PUQս<<% nJ<ܹO\iS:ƱZͯ?_;$5yaq45`;/9fV,d~ wU1r4‘zLf:SDfv9GimՙJ )iQJѦ;2Zؖ-ۺVK6amg.5{Kwϯgrh rL@OBDAO9J#Q8 Zjԥ·kATC!io467rL8_C;SAp"_]]?|-ڻvw{^waE!Gi+&6Ւ>{./ r=8x2csxdXXJQP7KMۜgLJCW *C|s$WGF{~ }Vlp1&Z6t)|ؓF?xq^?ܱ89IKZTU98 N\-Rꆆ̘7M7Q4x)"α;P&_p5!071eJesCrNqN=EDA9ՙ.q@3,/,c# Q)ZnI }oȟqZu?(ԒL, {H N˞wǂ3q.QY )*z**'Gvo BhUTsS98Bs8络cORsG1jdo JgB7U& @ɒ8MXAB,R8UѓD9"\#,( аK56Dhs"~ ]Oؼyw!ԋ=hqVjۓy} ]$ЅD92B@I!!j!q#L`F-,R޹ds iПxۖ-DۃhCn&ry`Ѣ#Urew43UDq]U*"5{QY(Ңe0Bc;KrEkۖ߼2w !5׉Lw/^|x5;S Q]"v UmxIK8Eiنq(a˞TmHtwc4cwg<֎GZAY~>7y|^ x-[nPfmb,l߱xA=J~ g HSPN8`,cǕN <>VCt3גFNQsR'Ŏqؿ7K<bhmƈe̥6X"8%q\c5Glޠ .㢇~\m>2=ŋg7?~(t.Td1ʙ'(z|sU_4 sQ`p1ҌϦPKXѪ0A 4,JfddH~ֈ- 20C( "2A 2Ji4Oq%gC6r|T ku#y%^\s .EPR9R..:2[:lUf:@**T+"R.( IYg Hqm> }jyWRH JNTp ;;OSrN T"P#:v8iT?+P(uyJvxL"NehOS8Bȴj0ߧ!v#eqKWA_^EUA^ ;.߃{ɒ3a_޳'}tvѦMsm/^2YI ,~pY{Nj3ilANPḙi1!gAGif(oõhOUzv‹𢊼$ʋAxمrp +hz}/hӦ\a.fKZcǾ)}tBmL@dܻhќ$T$;Ls9I*dAOP8AE8"YΉ/ sxH^PQ$ GlZwƛ:E:^ɒI(gs9M4Tt.pnX¿7#LaHM74k.S|\ ^UyYWWP^gB^οx}9 !z֭uC `n`A_h 55l_ yBk@ k4 %K* 'cAsYt:GLKˏj\ 2T5Ր[pj 6ސ(˝蟯2r,) k&~ԢA0L{nYAtq"aa}8o[6xq!LN8o]D  [hk1F6QKH^sj9]4#8tQS;ͬD(RI^iZ*RyiUxZ}\U~TԡϽohUۭ߱ g01 B;.JFuʙeYDX:=0Ry|s~w~NЌ,㠠4OEG/Hzg98jߺjVNDPkA<GxIDq9Nɟ.x]OZVmx)Ƥ[_JI Wp!@Yh? ẋnR V{ltҙGy p'{ЈE94+.#3!n>*OGŅg3w^9ºԬ?m (8>h}hQ+FUd@u yQ{{ɻym[j8iOyo:ND"**+pt97iշ򨑓DUYGݪvļJɂ\kjڵF%jnp3qVvTa@C[|s~OrѶ-W8hh55yQ%Ǥ]وTwXЬ[7#{CTxAGlsDdKczC.p"g.͞\cMC W}F'U|_lϳdU?ėd􎱴b2mSsW/DΝ=JB."#K*SE5dg~rik&Ѝ =-~a,?7-:JzJ \.tpJU3]kB ݦ#*a*^ Kn9Ajڭ6Q>gE:*1cvy(~QI%s4tqn} 'tuvuy=yZPy!&rc֢XLg0Z5N=u Wqx5?) af,}-_PxY@S.13<¥ssS D8VPy(E۷:6FTxrxr ֢3!`B}\B }LyE ըƸܷpUա o1gh40moBX7N'NFcrfMjӍn/ mL᝞MnpD drOJUGb009m<' qWT \ߟ]ߟII s0JT %K*>hbD'۷n. 0v"wPWП}ci>U~ngY%۷na]A~jBv =(A*"9|_Y:MamRl\"ܐP6Dq(䳜KnY7ݪpca0 h;WC/ߺit;Qd(LGt޶b0 8 )&D`O_MbPK09WoGnm_ܘ@7 0vKly:es"q޿?]C(aqCA|p8x5pQ<<^ZLa!P=l7/]A=uo߾Xۅ t0 r6mJEdCs^j>y?۶m;}$& 0QZY)j6Ր[=򙢁H 077M(nP aIU$ٙ_q# aAs-ATy6kQ4}77gM5dnaP?{Tؙ E@C8_.{hD@7 0^$W8z!sP}mۼh%ܛ0 8)~ Iojoa<8Yn{hZZ s0na` =|/B"t0˻/{q<& 0J&.,p ꘿xUM+/s0naVwG@Xׄ#BXdCZuaa/ "/<3{rUӽҭ[p?T.>6 0F)̿~G(z)qA5TDSХ[|j aq@v [g8DA٣w8DuPuC_>'n,jaZD8$j)΋ꋃs=g}}#9$aOin`e-UuU=J*d3%O۷ܯA&4t0 +z&g;!lޫym-q s0na D~$RTQMz ᮗ3˶m۪`3r\]0 㐡lLri-1W"c; sC⫯_ݯGm}堿aơG7= jEDLus3n#0w0fa gOALPq "{+ndM ;$"MC7 0Aߎ݌EU.'ΩN5t_m+`aFJ_܊=1fyԃ>JXy#|jwam4Q_s3|"! *5yذKյm۞|;M"a&^;3~s <<09+ tj۶=yiiaa1mHpi |3Uqк_xßoZt+}D&xa rǂW^\\h6ys!6zEO'#ton;ЫL9㨭o.XW/Vz'ao8?,^ܜz[?FǑG!ǙO!Ώ%}}})zWJ=%(M ^M1:7##σGe[wglN.+}}?T5׃(]!87Sӄ_x֭Co4a@qo w=ϺTA9 tL.*P+A 8!! /#lÅmϾxS K!o{"ǎBBd\y>,C} T3؛{}KVϡ+Gzv!A,6sy)vs7Bnn <42[W` Sլ$W_\Ȗ7|,^;^ /Sw!p,9 'sզP6?'Oi~N羧n$qI_6wai8Z,g8] td(?@۸w+@`_߉e j?!K}099!? @ꠃD ٷtú㵽Bϩ==|:\K@NG\F#D@| wCφGc;t{/t_sB ]zibÖL/z䑯;8>]Iy…"|EZ^hczFJ]9pB onLB | n5wr >^*y?@;ozvE2h_Yz-I4 e,ƞ2בeq{+0K6 e*/_}x?rI%j~^-RT \\<,RV/:cUE/܁WWr!'o}߈& ,UKDx?wT<*8 Rn/|xBBa-d_Rq;8N/u(ƨ*3#N Y? 7zg)؛A;v3#6P&J'_z/!sd2mr -H^zφmpYXV_siD>)eTCئ*"EU@8t;ıŨ5OȞѿ }/QEWS<ykxY$א/ܶ叡m嵧'>>`هNDD.!ĉ1 Nj[ oi 8`r_MBsr::Oҡ"aB+? qU.ѱ J:#t,[=G7Wо{O]z#z\.!?_{"4PI1C#qlLRYÚT!qJՑe/g/*k K?!*ǐ4G*YǏs' Ɇ7tw{!O?6f;WL^h瓽Kɷn}N=:6]ApŪ%AQ*y-B<uH妸bݮT`tZƥۛlӤdyHc q;J}0#,KW~}06ө@_˄TIЇO!$ň\D&Es@VPj=o}n3/s+#K3laۛs9Q(rDS1RE$R KE)Mq/E1a.X\rERg WbnPH2Ky.rj6$װgw墭%D_>?iƾ:]\@WF:;ޯB)ȅ%RMȳ5!85lqB z1V4ngYgCK4 rùT@9I 4d?yѶm|G7(W]~K\~|U%M 8C@G\>ˉCOڸ6!`Fu%q'zԮwO_Rq|B"d9ysKWY! 1%9\ ӝq(tL'F/[yIeY{#"< gp)w@fDZ8qlXF#87OC,[WT 2B+Oꆛ),Ɣ%7TذdOR&c X ,_}1}}Ul{SBhZlu7>-Z4Vy3M=쥉}I\Y t,/kmZD-8+>`*|@qǩ;HIRlq5&78* Z\7sEqǡ( <'zR q,6(z3S6ze> W Q_FOVXS]E Epc(I5!K_7]Cl1>A:5W*Df.}$qR]UιDd`w[w#lU&LKW*3:WlV wRx\bBZ, 2 $hQo6ߛu?y*4w ıUMJE@hfO۝|Sh  `kYinEs%jxhtөJp޵3EGR}?P6JQ3״qo&}"7S%A$!߉s>| Tii.ؓTm周[&AW#.  ٿ醵b iT^??z~{xfr0vQ%ؑNX+zz`-7SoڜWkٱpõZZ1k}oz2ok*KWJE4/UIőuo\ڕIY/̬?SES}+O.[7-{'Efc-5]VT;%%'Iُp/ZS-[TtjWq_aɒʍ6e__pqUBռC_yC:m5._R$N4P3W s$d>'F-Bˡu?49 ,_yD0]ƵcN&W]#DžCQw GzlQft$IQl8e'"5HÎRh&X.>J\2fR*Ih7V^5;F}Z(jwR=/hއtoG HKbiKlQ$OkrWgW]I:t8Ie.d2(z Άb|#3hB ۑًNyէUxG-G1QDeDFK/h%NCyZVjdiYmD'xˏ-yY@] "'r$!%fxsoQvZ{;ӖymY:| _bczIs ڵP~.ݏ]!*~ yZZ:QbBHD/@e.ĹbUT&0U6=ǾF+kWiX4|Ϳ$,]5O?pn>9#&>ii!DhP͟պ,)jy7U`yhD @NDdAOB9#@Ce'UAGfwvm5+@yHI]?Mm:TqBrjhp gq)7itl{@gT?PnEk,[I_HA/`=W{7oN_xOɍ;^u! |_艇1|~._}V*S?p 4OS[ oZj)qX^c rXzrIܯlv{H< ZlLDY(ڵ6I9kIƘa%Nĝ+ΟKek?ƅ@gZt̘C{Cf7*m,!Y$?^ 6ϣR~ZaPEd.Nqge˯M̩MDKzY}z}PI..86 H"'yK?}kw6)IIhe"3IЦ҅S7L*b I:ޅq2 4eYI.RvJZ^{P_R6iVAC8TNo*K?t:2#)|8Cl_Y:D}0W(Kɲ՟?]"yK͋h*!b2O>*{Z,zQjN>,u,f'g!,%daWb7 R' I*/ƹ=2p`Ʒm  JEʬWJd[x۵8g|kKW<̦S_O"[$GlZ8v[,Oeу!D? -Q*mܗ*[*_rᶇH BK+A%Pxwl} LUTaz{ ѐ7Nvs>iVHKG;iwWY!Rg5o7)MS}yj6-D Uk8֓T? a67\Ϗ 50΢B&qWgٵ l{<=:46Ԯ?Gkh ȩm*{ |JeF 6aĬ]>Ѣ\<&GXuy"gs疳xk/xd-۾ -|fbq2iWCCo+85nXŤ+9i$ezTg+f'pχR;FKF., O8e'*Y66.*6^}32R!Jv wK~%_O%|z,+KU.嫻TbaL$0<`,;M?Xp^e@s1Nj8+m8jX{?ϯcxOsE?(cU/?Vx&,).Q{0NFE6ȍQ @^݁'2[ҏ~vta+W&6Z*):8.\ql-c_<3^iŹ8Ԅs a@?ņ ƅt)`Y68[:Ix_.'1| 5Aݍp 'ߪED{JTZ3e\ͯv1vCN%N6Qb>=*"%{"/~nG䮺z1en],"DDͱo7V?ȉfG;㫼HSYiX[ܒ*tU<<Z~,)rW_Q.E8Hp s/g0N2бOʠSB}tw{Le:e$6ŝ/U>OTQ !K\K% vƾ%Bsc1L˯*BorR5n8ϒ* lpS.Y Dm{H4@h3xRgE!|CU.HWN WiWI7aŇ:f!|q5 9h2#ZRJuHz'9هdd4 {shY!л7 }}3w_T~6'S>b_Y#u!״h /!qP}RD"4L^CANrBVɒHznda1U;"}RDP4Zb +ޘbμ{H*gMX>[%lí~KNB)P)\U9Atwo_O@QXΖcѮxw^$|q[n)j\۫,]Ny&Ҹ(R!3h4Q:: 7?ۢ /RR/N|OFG|Ӂx?|(E!t>ˌ(ƈȻ{Sǽ}/}S a T:yM!^&-D¹G?E;ˁk/$| B="y8UDJ{9 6h~YI\V%;aοDթL|PU$Y1 KQ5!j}flWh]SJy n+~w#1'mAj.XT:YZg?[AʃAß4z*~?sf(It W}Qvh͓~E~Dg'q.AEo1a#yBvx1 P0qzeT 莙)yJR!>X\a?,mvfjPɳZA硚y7GWqk; V N7/"_T۠#d !\l,{Eϥ]$<МaUUGt,TACC-ߥ?Vcɮ\!OP\U:U/9X,~-پ]Ժe?~Rz(q;b,L00A{<J-~g}Gs{~ } } h9^($< 9 =ADwk|ۄo8pn*Nq:R_z]Ecđգ{!IB[]`=]̹s WQu:ރ]j8i?Pcē➅8$jqf̵^y?w= :C-U%*MPMnd{q~AQ{,c@2ƹE6gSxZDˁZ4lXvw_)InPWqIB:ҡ 3f(RleӍ+FQw.QF6"B/ [o7UBtqxsnYvݟ$?_XfAV~"OE䢉h=L5]Qq Ea.JZ']w/ܑhA\T:$OҩsE;Bl1Dwp" k%R8 l1eKp~)Y:*R##EmǴG~t'@eJFsq½}/WD ɱAMG8M#1 KI?w[q>F tP 8F}#c݅3(F1z'Nֶr[4[_uU!LOq U3sɳ1>p^as_,(Scvs뫪8߉,OfYR5{ӷk^E4<]GC'nXƺݞe-VII8=jՍƵ?Ǥ8TG liR yQE .Q$SeRE"Aua ՟v#̆8:V! _ Wfˮ9d tA(WcDn9RS%Yx5*Wj޾ b oNY=K*Z~$iO!,Ai91DYj0:S$0wsk1[]*@*kzǡhE| nR~Ơ_!whR]^840o҅qtui=|kbOܡKWm'BБq%LƾTF:4gxk`q,ywcK?˵1Nr"pbCwg+7t$)"%#Il~_` {IIc][Jqł_],.q9oc%O(^n7}r7׽$7\r6YNA>z0e| q #W%'@0a_z[I:~$MfT:ҡ?[w̧*̇g "36&#^_ U:״\E t.%'Ve٪I:l0ERANRMw?W֧@okgq->dڋ(g+LgyF0A+l#@Dr49sp%Ent0atrA\4f9˿[,~a0WJe8kaiX9K㼌xy9},jXXOt$J+ bl1SpT֦.h]}.,80}baY]/4SʁsHBP9 I)K!]X$5ʈ6jK'[h;JϚv.v9nbѰSi*MÑT1>12c9sۑx)½X (A&Lϋ1rNyMy+k=1 7Jv}9 1S\~$%twKjcR=h+^` 4K%'M/Ҭ(6rT%b|x/ scA!dvWsaRr< _xxT:sEfAF.\yYrSI;ѴG+KaQf}د@/4tG ԇC(dj>+}"po\~ NMQ=,}(A;0H!4憥M)U}jwz{$B4|%vK-DIVFӊb2(jsP>hkx`G-96&!jaPI~> ,P4d'*GB eڄV(QPA;?!SW7i]qh,T{s(jesdOx'Ir|lJa5 ;/8/GT`C llkPZ{Ÿ(eyQz T.aFX4AĹ؋ i>-_[ooⓟؕ+,ctX$Bbjd(9λE䖁<}q[tUpZSLo7>L/'ۧ0!NbF4"kAgu*ߎg.׬ P=1*@f˯;I]+s[WGBp,ˋVNs|T -N?]s|SAhKC8:,B9.Tc0ssTSBIũ.u'eXUo?vJ6)dzH!X ڹs,{ \Ǫa~ Z0EBWsŸ h5h%?$FeHNC3xD3U7VTs|UTl\ݩcC{4 x,B6ݘ4B5eM*:)ĥfV *JGKo#K<COK.‹d@ )'.-T'p+LX^IR=\O2M䛍wEϊ>sJGt ]J.pnKt(K*NYb<_k w$=)gA2eqJ5T}G4Xj?|>qO&) {TǖE*4諈{@깗d%]lF˧W/_pĢ沧XLWιFI~('?SDv&zڴ 4#D/ \ncm|'w0GD>NȢj:*IEs穱Za˙ma&o qS$%"Og.J0n{Ƈ~Hy;=;\ry6DȟQo~hV6 H[4R叱W)w*'64&F13$nB!.Zzp%Gs֤D4H޴DDwyKNЯDžHnWj13Pg]զB-"+iE}ybeqwU4T fu$q׽Ş sKWI_['ܳq^KaHkn|rCk~޿~+B`6 F*rgbp^mBm SE5fEo/kSdc~/.n Qm kIvD@ e_zbq /]aO'l1ʪ%.hKg,$ Ρ ;x&vdQi˵!LX 𕾝rZ. ym߾藞OW>BxOPIsc~:=;Y|!nQBrSwWD{)-1Vv3 (2Q wݠc_r|r$w@]nG|;0"$)&|06Uj_ݷ>3*|bȆ ˚m*oYuXz#?OO]amt5I>9^**9ՎD[?W.ޓx7LĞfȲݚs; ?~VT}JL8|]kb\O. .a#Ͽc1wikmQsZ B-^?S0]O.9e[Idqw}I[v`1U?A%X-چx4׊|n*~FN~P뉋@|1S *T*և>ȵB3w~Em^5aCUIJRR$e?ٸia!D8WM],[g骏Q鸀`4#n\3l .NWK[\34,],`Q_,>_ zz׻ӷ\4x-_yE45X$;}=m$VEG8½gЋ24k!^O7VOm<9B9OsCžsE$lo3o;ے^o(H[܈O~juO:AC#Ud<ۧ?AT0|1Tb&_eK~4 /05wV*nWawsLSüNoFE>MRyi=nG*郒I7aIV~tC`bJ&"5te ]mF1HliUVd@qG HتO!)6\z@N 3K>0iK,¦ޔ?/ydڹ8<#AJWȏj9Z_, u_KY \RIo }EW}xb~J#z=y͝OUʼn(_;8V9)H~vTP%h޷Xy돑xG\ȲG'? ljc|.$φkFqP!Kj}$IifA@iSVW@N^Kb0 V׊H m'@Kih^r t.,黸OwUc4x;8@HTȑygCkٸ KNFyTR|rDg^r}|{u-u fuuwp6hSԲLowų~;Ĺpy4dVO->ZSb&ү?AߛRaAӌ*}AO3ѫ/%; _46Yd8 OIKS JLJ,*r? ҖPk'{x뗣ٌnճ칼tBLy4-%9ӣȓM nxFU=tmK,J Ʃ6(4SjwJ%dy)\cmqҡg{mQ?L^N!281Rnt]J*/ #dߤ)]A@=sTTl}f...̲teȹXG4Z}Js{2|r>y:rAZ2s WtgvKn_=<3 ܓ{]e1@O_&DRMP{_(UZfiNdi^ Y ʿbeF.]p ѷ#L?}<$t׬4|ތ3E܎LRuij(AΦ/R%g6cDB$~T:Lrh*JE#I|wqrT KMya#d> \zpJ4mK'*ZTCkOFwF:ցR#_5F}rIZ6Ƿ6h)/pܶ]X8YPp׽xnY89Lm"N2UPO4)lrgieXmE떀?x1U~ QS-J.;JVɗ;GKQBF4jNhV宵ߦ74Nw<+ L e}+@(cu-tXN+澠vtwoK>q:ܞWЋKN*oeZ\j,#)EfOz4()KWE9׶g3K9Ζ]{  Z h3c4=lݧԴ(xWL7sk@kut\㳅&d5r7,=X{=-d﫱`=Zx+[DȾp?Y#|Ma[ Y^~ͻEv џ v}mfm)ob;.?  l'?+)7eGX y7%Ǒg#E3r,g6 _ `n=מ=xJsI#:+GsZi6jwsJw<4DykN#m,ԈP|ogtc:{.sɓѤrR-#wyoS@\e7{Q"O\<ɦF<4:+q!#7S$⮾'FhE1R c8w7*MGڙ +}>#@#qދqƴFsMQ ʱy8]AĖ™ai_X`qc0f[}ht}fFZ3QUd!dK&Y[(O9Ѕ<fgTϯX}1jMMM?u-:uN;Pޫ$'ٗuylX0W{{#Cft޽ Ο,5O[C+PvziE@÷pɽye yEצ$KFArߦ,l΍Tdi4dJ[)V!.yb؀H7m4"/sG; k39h='hxG"ַSXss 8;ϪȦ9|q{Wv9 W&4']r،ą~8[ŽIʕ㎥!$? q ?'-_L^ іjX3C >m~Yqq Baڟz͌LM۞qy vIΞUWTϜuRfc㺯72/JMR} Ud4/4oAyx4r*|y>:\իԕi }"P^}gT= |}59n _lf_Wfٵ%%Ңw/؛sڝԛB.o#:Lq5pn4<T:+>U};QZAN,G9k__N zfW8 TB?*@wuOh. Fo53DJGBȟAÎblN|ˈݸrzqەM8ϼZl$½\\ ['⹎Ms5eb%ڷ+c8T!;fTzFD.PZB%)\owl?q}"9'I46i{-2fv0zm\P~a3xco4^ݾzrzĶ젘BeMa)j6_S؟LHR_yl1'F@?q%P*Js\3l1GHkSR-K*iu&s*}=wn͆>"KP;]\E*zаm0}׻k :{Ispiݰ#|{^7x/$@@x5,+8U4B[kǑGI#BUΉZw}s 8/Z:6'ŸDiA ^醵l裈M#lk2-/W;?,%@7߹G}RvL}7>P(ƵfP--|#R3>g|b:yfdEl5F]\vqqjGѣ[^yL>[N:t7a0^[ KE !'Ptf'Zj7pY'SΆX^nָ F'E-(ql\ 7% i:;7@T|Gb8h֘ $/-_wb[-یx/cqFKM=ܹJ ")'DC3|2kyI$^AD5+=uQp'UlyJ Dd^N<rt];%8t\RA_q/7ߨYۋŝ(j=>xQ\:/]_zv>w=[>T>~_W)}"z |-,DLs"C6fwnXYjJtu7_i*$.%'dj:ǪyM_6lח. IbY\E ZB.heQ/د쾓8}k py=ʿ+0e4k0VA5$Յ1]k"H1d98,GUh=j,9?Y#T5.,{mBU9XQ h)Uj=IstfwKf3_ܣ[,_yY~j烞rT.{\7cweZ3`Dh!DRDh$o(ڵ縐KCXt!|G_qnMsqwosEChރ3.}}@Ec\}l͑/i bK$]sq~&IPC ;Hu K|\6W}/I&$#] 1xf̢.2 , iS%D?<{2OrSeDl(+pz:#Q,8xVST4*!MqwwxîCwNBX3ܻ鷋Z#!}^%o.:'"HӴӹ7eKxdc Gȳ똨brk//׆ҕ5\O8I"G[Fg4)"o GEkQ3ORqzUg#ˏ:]TxdPG<%y}T.W{t0cVNMoxT K ¹cوwBxpAS FY8E98$CuQ:?vñS}+WNzB{wzsX Zz7 0Oc߉24Wդ<9eLf*kgty6H@'Gd̿D%}w5ڧ2j|:P]T mY*Vt%a ./k.9־Q@Uv͝:F,~"W\2DTy;wO5˾<lO$|24[BxA}rZ,5̄(#\JZJf̭4q6zxe?>Kz:.dpkz׺w8޶3AoQL͉`e`M5I#=fYF `}˶0IDS+ࢱF0>EVO F#"^pv!dڬJy {V ;e0pѾ@,^:^}&=2je؎/asI=#+jٿ-Z48yq?Pvfy&-=.,x5KMn۴)';Y6*W8"B9QHm_K}},](T:*靺ӭoM˯;z'֦ybV0G\ď}5|w aKVOD3RA?r #IDžCu~hyC_ʕמ/9.[tsg9nZ./wT1Z&`d{j?x mD򑽴[7TnKTشiCC3wKWV*WMҍl\2ePDT^{'I22(^ܝ=7hKnƥoR]=La>z׺f(̷]}T:#ĽoT8kq]m,zukSQL5J+ݝ7<ퟙaR(\ }o.:;wΐgM8$3~`M׿)1f:݂#dA|\"viVړehR߯ a_սCe㺗O&xaqg\G%Ap(ޓKmm?[MT::FƂ!>|GFN۱zr.Q ߣ=G]E2[/I~*xpf ^} ϸ9CfW2UC¸msw=7oguKQnx"_s6YKJT;j$i<˯KjyE}XX3!æWۻ {wWZ& J++i,,`N錻 u:͌L Ӵ3nk,d;MC BFquLmXP$0b_ڽ{|9wue]I _3;3s=;1rA;h]]^/aXZ/u~5{5SV/xHWM[YfٲŃ1͖.RY|-RBlلrʕۮY9:ӺwtlR9*zL ״]or6LR_Xlړ`zjbAUG%>u ovMߙO_s`+Ʀt..hϙE+x]_낆cӦeM^sIJe)isN|CǴ\Pm][j@hzQ]ltsNzU%v+}rAv{dܝOຓ<̫-i|uWkۮ\8*!%m@z&6n_-1o|JEgr+'l;]7Ƀr[tmF>/tO% 5 Q!W,7}Öj$ḩguE+O*X iV+w{#/76P$%%OJRq+d(TV3jrn4xYԎy tƕ*'s5*~D9Brs^7T%ݥM*K.4]_ R`YnY12UWcLCYtT='9enʛރ|i.%MJ6}oMze\X_QFWSrs cϩu$Zgao0J B)KeR,zz$e|_:b@!W׮f0ݫVLU+q_,puʷ.\iQ{SRs2Y YE}on<3my\R-Ux6 :IR*˺DlӛRU5߮k?Do;t`ʯ㢵;m,T3jiU3WUA}k×$3yYϯ*ؙB֕CTf%w<݂ؼ\&lh^W;_{ݺv56dynn'WYkkU[շwouYSEQ.wxF#'MM ABj4'#U6fpBtV&$5V-|df2,v)O)/=c>/oySOP@~4ܪzʇL'YY-{mړINW>kO^k6WzLv*ğ gHܤՒ/؜'Rٮ>FKRyzhTwAJޠvrLLmgO23OZmodټUe"5]àC=y{d5 ]N2u}C\nɽWxh_:BOnY8HI`^oX{rҤ{2;(gI!Nx)ل]cxICCFk?͛'ߧ`QyRYNy ziB)O(b2SlֹZ[u` _d!( yR~ܓ6{C}ُ\ulwB(s6ף.ԑnUtvU/l׫"l2[h|J w5u)&wܪI \ӷnSI{!_̗s)y=I9';Z Gh<6t]8rY٥B !K/>w{OkVfc[xd^~zs7sDF53oޕenUKW Y}ޕk䶉Y|V֙V5L4vWLy?Q}<罟g99&T%m>쾾!rJN{'s!AR~B`m+nmuzY}V%v_Por@?4(%ߵ?{[Ҹ\cPߓk=XhWsNMK ?k#_#$51IGL?=W_`Io\t{%\lK_#ܱf; x^o]-1 IYʡ2`cx?*[}ǿӟ?I`SR퀭t?CH+($Rڧ"R~{n'#ǩ2nK{}ch_-%=i@#.3ȷjOj=Z:9{|/a]cںh`y~wTW!v5vGV>qIwhdddvݎ?;ۙ~e_'9|2xI达9 a"rIJ@}!D|O;vn=^'v8>^rW[D[8{WNS; o=!Ć&)3<8<:;imx}+JZ9O L~_?o{:[GN*.XrM^7F^3L7,ݶ~SЀc@RYוx=o vវ=S9 vFo… FSܓ/s~nON(G5m;SЀY;^Gهٗ慠q?[ VMLAf+t3ҽ~d``Yqc]YIc-Oo[HҽCC%##̱BpL:׼]gݷ}?Z8%';v$0G_Y4g?:G-}ϖ׭׹S5vYe`Ɇ.^ownwhp9XAIENDB`pydantic-pydantic-ba0aa01/docs/logos/cisco_logo.png000066400000000000000000000161231517143232300225120ustar00rootroot00000000000000PNG  IHDR/PLTEαtRNSlo<,W'I {J ¬dV~71aY(֣$ɹuqiF!ۏxB9ζ?=˴L4#ݼ^R/-*矛fng\UF;OKӑmѯmQOO,ŸytpnmjaZSJ4Ͽgd_@99965%ŷ~{yaFBB@ϼyva]ɹ@@ ,IDATxϱ @@ktFD 4Α\!s&DpIރ?i8 ȧa*mi^}ӵn_0Rif0p6]څQ>㯴fZ8ukww(vw'v ("օ^Xވ"afvW\n yef|7pr3y9%ihGONg0A#)DU+!F>ʲSXlZF2($VgF/6WVܰ5ۍCA!UW!Eo x7ʢRüs %zܦ[l­U(G6,Jٳ5<FC6MB-;eM7 ^Vv451e!zq\epHG} ; Az2vl'] zjڅ~Q?9FG/ɯq.z˯u.}ᜃ ]G7=12}V0v~1mc\̘ѯ;)Ћ^Eւt=ׂW#=gl6K8SǤsY-lDMxU x+4ɀיyOA ?ΈݮQw=mKTWjN|?|Z؁K|1FnNȧ܌H8/%7j }1 ȷii+oȐz4|;[Fjhg_0硿` 4QBNX@jt( Ϭ:K'Ln;+PkQE%6nQCqT֤VEkXm]ӵjbb݈iKa]Q98:G:뀣styegP#erH@:7T.{wDZ޻]gen$tO=3:f͓D+@y{WaEU4KcEcWFWYj_ōNTO\B[+LYHXVFsnY^&z#Z)+Fۀ ,g`z ,Ocf :Ae7NjY͛3{RiNѬҜUSHj)9% XLsYzµ+ 'ބᕮMG\.r\.r\.r\.r\.r\.r\.r\.r\9#xIu{V:Ō'}IF/>@EV)KnȖKK/7Mlk=+kTVl5Eφ)"ޮ"+sJ۲jrj`z$_멧S<+yAIд̼Vp*{Ȟ]zuuțr`*6wf*j#T,gJ W@qtdBe8 W )nBP~nZ&ym4B*xo˽J)toS4=slFfVeF"# % DՆ$lZMCi/Q<ʇ%gfY14XRms5X1|ŋ`ln@Z+nPF #\X.hxп>{_Fu8X5`)@QdGbz/F&E?RAѓM"Q ]57(P,F?Hj2!E#EjB"zq/YnR h.֣Hda("/-U2R~ DR_*E0sI 1z3$#,ߎ9T@Q/i}˿=+sj̦[<8MJtO-8'ɑUN϶^Kj¢<+S`jdz[.*ۑPn̍^YA)J:L"0WaT'6XҰ̌>IQt@{kIJG/krd>Lh7lEK6=BG# 0AhzRQVF=&rJ̛IU ֖D-d"~u\'qIk D&_0&8IJFxx~ VBDdk6W]Mv9WgMںp"\O&?@UD_%CG!RTBGm$S^h\ Eӡ M19HPN+0::!XDrC(&яK P)!Gol.>LRSlS4#A@نIk ` i%aXE?[:K?%Gvz,h*)w)XZ/*e_|jRNj3'Ȓ/K$ ȌE_Ζ!g#9 Xf(Ԓ4&֣XG ?"j6!#@<l%;űNax mޞVD{ `Nd׀i Idrɩc)o{v.p菤ۜՋeM ɆSK$ѩFHЧ&qz/ٰ Nɓ^J\D'ˇEj:C_᷵B'8NTj"t<@}3%S0nu`ExC e&y([Qt+(rB^"ˊvd(ihFjX9No3:D򼭁SAECIkLBșLllV9ꉿa DW7rɡotx>e@ ;g,rf] =dMM$I`4:Q!,7r`{3i:CHS 5:wkSȑAAtSػ$ӱS84^S t*xrN8,5*z6:5X>G֬;\@D+K~YP'/0NP7ɕ5= 6(/=9܂\NNH-D>-WH`cȁ5uLJ&0y|Bmqܡ%1 WoJsp; u!tQ) t8P!0Jҭaz $j% xw!:_'ED"־I#ۙ ClM%փh@[,v@0s5$V3-JU] = Ԛ^~0$?kU,,ΈiJQ}u1ƴ0]R`Sy6 @hhhS`JQ 6h,MMlu)SO~ aC]P?`pko抢[zIYzS.XOnn#Њ[XL?D?kcKv Z3%2),\2x љ0Ưgi4PeyM [jxĻ?]lDPEˢ8zGF|jsliX{QeUUJ W-AL sIATa}BQlݾ-~#g RI4n5?C1!'i!"=%A"迳w//QEqa(]1y3cL0e5EARӨEe(ƕڴhk\3b"Z5Diwƹ|JÁS`Y@|@<UA1>D+Z 2ͫ9zA.x3!EI\]Rmtc%a%w1= )?O@bCgHQ(eAfp:փhcDRta(jn)&HzϗPaPۣ/D J.z ;TF٢ŒWC,] Δi|,[!+!UH%d$/( % VEC藮vY{/wy^ vz  'eNj# %>kM$c qN)7A+rAZXvݽu5p T ><[& cm_ YTRMHB 80S|KE7c =f~VP\TV+Ф\Q|5'N?gnjupj&@~zV࿽1饵M7Ziv+v-_U~vhɫ㊟Ht]ᳱޑվ=`ӝ哦sլ͐W\y.T6뭼F睮Us*;kJj٦DeʠϵݯTVqѓģ~՞wәNߘkΎPoc̈J ;ٽ1tRNS [RG(4;h/b@"~nެsxؼvzԺF)PIDATxf_AUUUUUUUUUUUUUUzKN0 H@ USs6?B!B#l>]%W̃xd(+|΍wSy/GaS| ?:2x*}|Hs%k Ig||H\|M@69̨`+?qK+1/+jK# D=Ͳg<@# Bcmf@mDWӦ|J&ص{8y,=r}---?dɜ!,y! &p:npvpѡ\:9'r`q(GoS['QdQK EVy[b[(Xs+G21D- RnZi 80ɤNGYz[\{ -j'kL1+ Ko#_ۋQ躢;%?f˅ )?wex^M!a)U5Q^Zp}WE3Kȕ=xPGO\ xѽ5֞Xe[lCy^ Q8ƟB^|lV,;'eL=dnC ! ^!V'7omEbQ4OwpL3쇁+fo>jWbÒgB <怴WfB2EN 3|7D%-Nw,ddbbc_fh}߷9I>x0Ό˭iҦ!"2!jM.x *BE"=wsʁLFIBU&E={L| -֘IFz^`뗀EUY S.4˒y=·l)4X CU͚"0Y 'rh zўTF0VLaŹj]DܨuUb/}hLQS)G*S㍬Q`T\ppR\zIQ; Wr ;KMTw G [͚J9SF0. ]',LՃdrߙK^1 `cZܩXt{|L&z/XړR(p ys_9t3YT, ۸Q cOJP3# 5$zsJ`3~;$:W ǣA4*U8r@A=:{׉gr~~1-K$&n x> dt]]ŋ4/VfTn.-; ڋR*5]=GwTKqڽs96rY>1w}>MY/Bj9%:U=yv.{ 3hИa]|w,mx6}}W3 ȭ.V{_Xi[n7t%=J.Fz0e<&iʝ{羔KJ\`3w noeoT#*~:piܼ=]/WŘ2~k59͝o  _wk];gԸ hKWEET^QXҭMkv$߽.u,ץ9pb(@Ik+t/yKvǽ[Qu/blޡWQP n߹ ~}@=[JVӘ>;CMQ)gf]yq,pZRW?y|’M>u-t/Πk4/N#w*?/:0Bj1]ђmN|aÆ;O;$[M\E@ B>Vnvԇ7~}SG] NR zlEټ-N\Pr A^icWM=} TTT|Uܭ[}Zfa/;g운py&͚?ojx+%Iyr MQGOiS'L6{zťSlޯ%=ry/dm֜ 7GkR=vlP  l}ٺxLKG5߯Ɨ$YM`yz jSnҌm=jS&:2bW7,~5g,&e3f9l=z>0h(_0cɾdIt{ivcO\גdI$kV ^"!KB,/i̜=sz싉8I.tbSqʟ25(tQ ڕq9L_^(eP{)yW6)+P(fhڕC>8o.JS%tdVx Nf)7a4RCVRgĩZFsBhZ)7;k 3~Hݠz><DZ\n?V$j?s Ns# hz/00r})J=NXз}άV-Z*q t?y ۱x*Z:]M .tZ![ =K/Y _!]J])f\⮉&3"9,e OsT{KXʰl'߸N/Bo?V1xb7S \5dyWn&f f %_ppԥoh u](Z)4{1\7cv'۴=qwR ^* ? _~1Om-9թĊΚ kaԅ.üo6VrIt:fXf,̺-`4yk'm.ɲʧz<ߠcdDZo3  rw!n h[3^ʱ9v%5cfA)eJrIέ$E╟u XkI̡D`B{u!? 5}`fu.eK ;P4sp^ghM>rLk)7 -~Up%W2Mk!r̃4lkH S"fhDZ_',[@: Up&:Wg}sC7K3Ry΄5דac "Rx"\I$k%ugo#- RhH`fU*m˘'akVB$C`f2KLL7NkKݧ%Dg6u3pp3Mx(ū+3GpqPk;3{'ܴq|ԙpG#3s-&KA,v>m[A anMG:[0ْr5J `q4FZ9I"Y 'gU`qDAh%( K30[KA],Nd&$YHzI ԍ(2k\s ?DC@ך.X15J6Aa%'xߙ*$\0T);OAM->-('U0g&mŎևF3{@Rx3Awb]mU=B JaTr jb]XIkb9ʖSPkmJ~L⫕iR_bMxʼn5*̄,*U_}ԋ5+|߲}+JaT\*f~*[+v\EL)K)Z)l؈ Հ= h8[#A! jciTrʦկ <CoP$'sF 3X1`9 k1jE;Y%kh8kbbfoT=^MA\pπtd83!lU,F`)>pg<Ц~Y65[<"N̷f}TC K@s7q >ʮSP7F:K@d`/tS0-y+xKvE}ǀf]_g< L'3ت 8F)X&ٞg=ضw4],9H ugUG[ʪEE{fNnS-vpZu[Vк4ZZqmbq[ jAT1$,(P9E}羾%O$s.ny k<$3E31Iz $h^:K:+Ő̷NvU~H3"S(hp8[k:&GDoTNRIL75-+k=GW<|?[ 9nFΕT҈}-LQQnƏaJa%iL~:=p#; QpZd3̋Fk _/>.7k<ԓD4VS]@7TvچAHddS(f/1S\ jJ .vJ[&CkUb*9Lє{Y8,t[MM5SI!fk 5dv  Ok:3ՓbZg:gZ,lrtTxAgd"fYw5։)M#B‹k [XS(f55VGFj ɀ]l4IL)s:r"hXƼpUQ&fvH9S,ۚ`bJ,fKծM.r+ڛȚaݝm{rZssrsznnLVS(cRǽk ۻO $ &Hm=u`05++''/57uލkVu r $3uׁWP(<|>8'yw4{oml>o rZAoۚ$<&{ ФN` n_yX‘p׆ōVZ'ӹfS3[F5S s)6{#<HhvɸDf đ@ՑW4Ub)~1uŦ`W$O G=+Kk` \XZR<|(~ W y9fֲqSZ11%neYːO]4V|=axpyc45fAsݬ$bfII Ð`.jOSG`7#nM'HL KSm +1{y1[a\D7#X3EOɳsQ Ò6x6{O,[TY()vV z,_Z bp"a'9Us!45=3SnF4К.oE1ZkG@X;``|7 So&u3CpPZ=u^sE:05AY)-i+0}LJVf5qS0\>+M׿ b5| ~;i% @705 BAk@WSn~Ϻr%(fѮnvR%=* R=^CŌv5wQ?ߘs;+o]Ma݌OGvy)3\<۵bjc:ؽ7$L t3bF"Ԏs (mP*(JASY8jv4jA1#>3IG O:卾R  t2#igKl7 0532 G8 s~IDӍWެwT~XA1#]wngL=9OB¸)F[ +0H>DMqbӮV~?QVT7>t$ʆVG7<Ѵ+/jCwM⵲DkSqtw}C]+AbWjp{v fŔ}P{Dt90GO-*hPl%V\ȍjX׸Xb-[^舠 `.i4тKlq( pv[<*(mxc==* #F9TǼs1 =gGCnHH56,i655 hŌuu55] ғiǙ\ޠyYZk3G+дSzg'#)^1iWlEu1!6lv;\F/h~"f bws[ 籉$=g!dDL 3[8;n(v*wGS㦘Čq 1yI wH:)&1c$Iت*=evq#b3kq+Xk<~71@550nMzy,|gс~*H550nI1n8vO5Fn^L,4 .;jj;I&#ю0.&AcG즎s#2bF?7a#yRT쪎0.́>.i>0#M(hV5p>D8i!\}򆦆MЬ.^97 /jG)=L: {%Q7\p(՜ۘҒ)%OἯnXӕF63XFVWlrw#Cb5c+',W\-}M4HӑF+km4xdm,qiy5tQo{g#~H|$ _2Ö |)fSJJmD"hk%+)m6bA4B™3;2W8{ZF?!b#͐M !au9 rX]CDٌtzav' ^XyČ\c3ґ{Ïe^ 3u#q;or2MRfcGD֤_o.*X%;8o]sdY!˫^g1{`cTZH~ݧy&EO,BK|bՄ4=Qjaܩ!ayK )`~pc1?8- |xC;ߔc[ۄN8ۿ{4\74)kyF+p1K~mJ[4j^xj7 CƷUj9c3wݼhPp25j<+Ӌa_;h}UU1+T,<뻗Mŝ|$PeP;׭B$2MS9QG,CA|FJ fp)F)^R}O! N!%E`x))2zA zyD)`ՈQO͹ %#( ~ HdkZրTM}. 5jSvp߬l$PON{jt.Q}S=e2DfbA~k#*!axC+ :IENDB`pydantic-pydantic-ba0aa01/docs/logos/datadog_logo.png000066400000000000000000002032551517143232300230210ustar00rootroot00000000000000PNG  IHDR@@~sRGB, pHYs  PLTEc,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,,ltRNS?]y8Sl Bcަ$A^zWv9Z:Vs(Gf6Ro43OK>|bDe![x}yxOq+CDDVܼÆ'z]"""T,o'=Х"" _t%#G5iiZG ={RKOkGDFc]_xz󵮉7 ŒgV]x""C=|ы;%m 2z2ӣjpCADd]#<o0džȗmּ˛H.cDD'UάZ}9`MhK~݅) z؈pn^T!zq7HfK>wjqC햢Hr;E e$"RZ1S)1zD,{횕kjݛ|i5z̉$+> b>0=DDn_k!_pC7;oP_l(j? ;"LDwQbpbM)5Ggۃ(< 7n(>~pCA7 G?~a݊/!3ЍCDuyNo2W"iմ-=5l= ys (,>Pps b#(.b]% "ͷ+k8%o9Rf>Lj(X:/x-'lDwl*~HmtѶ5!ݷM>"2y~W4 +Qǜ_\; ID7e9gXh(?;|kycK^\M,Aw(w+^bvK'SэJD~qsU,ɞs-KD`gW9ѡ#o"gA.ԭWhjN; f{?O}ɻf&"-y"ewAҡj"R_S_D jno"ȼщHί{<[o 3 OD-4_(.;ܺp|#6pJ%@DNxjcΟAa})MKF R}MQr7kCŒߜ8?6]ڠ п$9}Q I q諅x\}ܢ]%B_>Dl5+:" ) 2ỏW>QܼtC&.$]Q5Gw(nA_`DAtN=w8J/4ͷ+G(٫&ҡ#2A/RB_zDа˘?$2y~|?}q*:MkwԪh|c$ {(w˓ȟ2^p\zLÝ]ї(!-]8kJ˔Wŋ\[5Ǭܾt֌|ܕJu5KB_uUtl>3UJ#>4NZC򍧚I1'Y"4u}qqHeg8k7Q+O쉾c yoE*V"p2#*>\F>Uu84SEW,{cV\J{k-|4=EKV޽j1T [>v݆d\"mkּ w.|}Q1nQCmyĮ_"]WnĶK3)7>*r iyGՌ[.E_Bd=7z±o{ t[ɷwT7[G+ADD5wq~;%CqGg| b")qB֧yqu=met60H$eࠋ{/8qh+U:yy/<ׯnn3NJ(ݹ3)]H"qNoń.a[_N a㫟ȝ_/Wy /k:N>'K.qkș\٥ЭNaKV a=v:,M}ϼD/WT7v %է5Wvtks2 f՜GGn7$?;y;=}OWBNCiEwIO [duۭ2OjQNC9  Ld߇κ|MCrzm|WFeVlY^yޮHtURStTpZ >߼#nW":?<˿%Sqq(tGw)w9W?T5r^ sMJ;u#:dl\62uMJYE? ;jh<2&%*W[z.Z.)+KKtyU9\rD'.|%9vDAfG0Q ݥ(wx"K݀PBLLjۣp!G )7P}]QAuև+Z#,N)D6q .IԃnM19ńAI}2CYY0!4bEC^x?B,qOaQݦNzȨdʿiBE1pUY:Kژ;Mp+mcȖG2rY[[;8VՈKfc$nH9(6T?+^褼j1H&^N˗{*<uyVhTJoSR?щyeXsѻf@d2}}"?`$P9(Bmޥ[4^磏MK6N([TMϦ.R Rݥ:lm42bsrqOK(T+&8/Q8tǜZ. ƽAVݥ-=MZC'c֊||?w*dԞ:6-#fjWc&1VEAR93Io|T ws7Z%~ɕ?z)tŎAMU:ӱ 3ϧɉӇ}@V֑{b5'fV~}caXcVY=Ft*{*ϸG}9ߞn^7)LFJLŞWY-ZVjMx'e:1/~?[?o#v(oajĞ \>Z UitJk\|C7d N7W"{jţnKѪ+K2 U^OY}4*X E6P͘UճeySF?J[4}\O3NG(%AAnSI[рUfdx* D~MC'(eZ]f+vPU#MDAU=u#RES]Tgw*ћ^ȅq$(ƙ/K_ŝ~񿫤JHGAt#s]wPifk;;q-niSȊ˔L"ҥKϾ^JGE&nS @dzܒ +bWx!q=>ю]PB' +bP Dw'Y7#3B$QqgOȳ\<z ߇1[DԱNW0=}d]H=Xq-I8g=bKOt:Ow8+OT;U]\n޿ ˛l5ݻv.QM@F Skeʑtc}kUEK\|(`t7[FI MO_MCW b2%!7=§ӃR/GnSӽVNSc5dk-E< rx%(x̘2 Gʧ~rrZM=2/>mng^ČhC%%K_ƫ`Y8Zn<2/@t|\*,6-27ɧ3K͖?љG_FIBP܁Sjj]S>h'q_que5g}>3e}."={Qqcu ȟi{U|(xVԽ)W_y۾\I;Y ` ֛#lBKsg@;u~3R{ VHA(h>C+=<vvM+c=9=VWd)A5Suw= GuُnSĭɜ6ؓU&`G'(;y310M!e1mN@𬰣Vۚ}"C'( 5} @c,#/<Pz]JTWU 8+}@K?3GͮT6VϊUU*)'t*U]L2'i`V]T%;VNzS @`:lr=3HvM3T\TJT N֧hwPA(pNAʃS*ÇFm.=vX1MA (pԆŷ kW?2PAN!9a*8[" P\nT:j_*GU`cӊsAۢg)t?{~*͔}ҿ~́G6C^K-:x6o NwB/)p㰬'wRbW⒔֢s;\l(HN~E)v1DM\Q*Χ{fov8JOVq7VYvHrSc\ŝf}msi [}j42H~)pև"';*Na?4R8yv_QOV'{;/lHxLET| C @Sݧ܍.ayDuJxcNY')s!hP[at8Iޏt㚕[G',y=()x}jWצJe#1͙oDOI:xeN%S܀nT{fE*GBDoƾ2[Sby? C DϑDw^r髓r} CSBgf|rj*ǻN0^td}qz9OGQqRGz;i:M_,b+Hǀe.Ructw3́^Lx_ɜ%JG嗋dOCNF1r;IX+\@;IP} { v>Mut<Z't 5`S$33y)K#q)x4^ d|^WHe5#h?O[rdAI t&5oo_*ޟHB<<0E4ڎ SB7jb_DڲGؓKdrtZʏ7Fz3'Tƿ} i+ƛ)^>R_袤reNC b+"lǣ#6N^GC6 ݨ1ޛ.Ij97] Ⱦ/:7k!ei lF}͉K={pqwʝgyRs50=7)֠5zXNoNh|4ˉ'U\:nΚ7tF2}׋rCV79aMo5u[-o?FIS0@7j_Cö`fE%×Fg nSkG^mٜ)ƣ5l3޾:lFnA; Zp6P?uy}]n\fl ݨ֡+/q2K#,synl'Z?@4X#.2 >=bٺ:T8t*vsh/%|4O} ȍ݀+pSȎ:~GմӡEc-p7fLA$Q3 ډ ^¸QMr75yPz'0Nto]wt0e;l{hIJSo @X8U0_ эnD; yvtgUgakiӅv=+yq`\u<lȠ :"zst;J 9YQxt)^Ƕkp~D5Pck}߷իl%v)s\`n%*ߥ#r}>jQU׭˅0d).JJ w"WrՏ[R?){zXe. JAأC N#r %.'m{0Tm4TlM+!uIJ֡ClfK/Gfr:pgNR<؇X-_%zy iЙ{1"sPr0HH\D ))y4}k\&(&[H|IpP\D*9ZBmHwVW]"qx`Ii4+tvH-Sw#'R?F≘=ZRYt4blϤ/zmxLm_Ejɓy@ov|߳i⚶7Df Xiw$ᶻWf^D$&7[:9gᥭ'أE|fg_YtU ?Kog}85Z|Y!%@yOE?27[&\s:u\K-cOS챵IRLK:dkA5!Y7gg:i I)4/3R@/" [2͢?!w&p{pxt6{em nzO@2J̴]yCIzZ=a79R;[:Rٔu~G7CMQI?ߪ 6CWzN=y'}.Eպ̗QAWwUΈ[ȶ9>frkSi\TcԨ;6GCVv1w㼙yN@ݽ&H𨾖ktt\Gt8dV]wרE7X#)aD Ss^3e%nA ~$U95[z6} 2Y5Ҫ~}H-NZ5FGDx*9N€mKU#@5YHN#^WKYb΂(- ~bST'nqbIPpXџSfln#)kv;rb13MCGD6Rٺ SA=t‚ew:${R;H}8PuܘU KttDdg6oRQg3S@˅|E^utDdǡOTxqs/Vyj1u No_=jEsY4(=A&k+Cg+l}lKC"[^;ku3՞Vv#Bfj+?Dg+lM\C"{;O>g{Qh鼧?:Yi#RlܢPVE <}2J M:YiĥXi:&\sqU2!3[4ޙdȮ4qnA'}=9m#.W!]S:}㼂2wz:Wy{_}us즒=zў;f$5:&m@}o5!C-tgU iP& Zr=:S>Jm7pȐ!Ւeљ0!>|ȁuix?:٢mqLU3>1g<2Ϻ:Tt*ԏjUȯ̒x=Huu)LU(`(2׺F a 9S%`Q!3,Ց'3UD{c"g_0g&{*kkщ*Eנ"gt {=5utJetPPG4]x=&d1:rtJȴ!5iBS!ԑ$sEASi 1 ="d:2Kaeej{tPԅ\W1Zm@Jܫ#oB'ƥBEXG Q)V:0eKFKSCNTX9 ϣǃ TOCnF穈՛Ϣ"s!9z8_iF<gkrl1HAROCY%{#:*rnz.#| 2ݚ:/:Q5J[:1Rӥ`03OSGvG'~\4CEnt-|X!nԑUdUw"7t1_KX! jȠ.pUG"Wt1_oP!jЙU"wu5^P!tud5tj|lȕn z(5ud@JtXrMWt:7TSGޏT-w# ĕݳ2^]-y :S5ʵ:*r0]׃C:]-{:CE.}OkǠǁ OWKvNU ˭a[o |k0!iЩ*qe[ak;]>v2zudtJlBtXkڮ2}6EX\O@E5vEWO )JikwЩ*Q2׀s c[j$ =5Zt*oj tX. j2D}My:WO*(A{2j.3t &2DވCu7O8Asgm.ȉ eɛwEJ,.y~?.Nt t8Tdy:i17_-;ǃ&4YXA謥$a:sҏUsqcEJR[F-dSˡc br&9`#4.ؑ^6Xr5:p$i5۩%& kO bXMlȦ{j5' :ܑ17bu|@ƌ p[%O :zkG^s{@/@ ݫ/agꏎ/364%!tY"N& ky~/|V؜^qgt.Cv}n%pj#gǵ/8Y"y :JX} CL`Y!܎SK3mro TJzCaoԺ)R;Oُam:Z3Ӡ#CjM?0݉NϫĮɺDnɋ.#ߤΨ":Xy&swgȑv5Kхp"BXG[uoG/sыcF bM'mz]R3c;P4lV jg7A#Gyݬپ8.m6j"OOskF.:93yEJ~teL `qGzR'z}"3J#ȑyZ5Cga'gH%tYʝ'483qKv;XČY#BÞ+eOVXu޶Щ8%HmX) ̸{5GjrT@GDm y| "" &BX^6ʤ2:̴<"6.+8%H)W^c7 %^B7k[Hn[Dy:F\}.SC\62&նsMM6$z9kdjha#A7k ?{^ N>)K ;ha#nX~}2; Icd6nHg*ø?A| b[7`y w7D(oH\*f@ޗg.{Q0&;p%Hff@j(tQi7۩xH?)!٘A)zaƌLnV+~]<z3*#<&y#WEC!$,Dw[/DJ3fzUC (#7 ` a؄ݬJ@ł*`"\u%$NĤ&י<<'XDCA@7ЅA@"[Axd {?GyyBfh12_fM*dqZ_U5Qkܾy9EF12ol\]h_: UCqDRLugŢE4¥#nք]H>M!ik$wfӲE4txD7k%3`E/ذs\rp 3^d"t&s~]tux> A剻;b@..bLݭ䃐}~i&˘'O1E&J ǡzQߤ=D۫x2B{^7v1Ze3} xt]; *o{;fBz̦~dH5ݖpu4ngs}-^E++2fM>8Z n Ȍ=Ugh'kRf_kNMg'gTόێp@w-'ofսp!\95ΞAb@(* $9iwĭO]ƪyU"қ5y UQ"#9S 2Fd$v\ljrst6V,?[t: ^>QSGصz"Ίy2Bdfud54Cb.NorfƩ˗~M笚{V;5ό 9zQ^f.V/p*]MO~+ cXDڢաWwgw5^mx)}}g@B)z)ꓑթƛTQ]uC6pcvgj.$S9/)o&BK7:i.y1ɯ QYBˣ~P]t2cnu)kdrǕTo1;Os~p4Gq/[])KAtH"h'hNOw}StխƢYvdL6,oyd蚓9սy]oFXO&nuBt$*_F%q;Ci^]t2ndyJS`8qWhO<%z袓9Gw7x^r[.8%r#1]b]t2 xg}V0bSm?Gt@1ݭ*%JQ[^NL+P!%袓9nGw + iU.xT褰I2fֆ2*Nл:KvJJ$RHk袓9ʡUN6>1?,N#,jt@ל VQq ){veD%;k 5'F}pNtϘ&ι"3{X>c҄z@s]s2PtP¥ ĥ$=JNUI: a\'-/f;rm/[sޑպ\sWO?RNl(\XH!$|}ȵjj+5/q 3f5'sAw5މZS})NZd?߶/ZSt=.j]Yktעh}?@t6} /AS"B{t n5Yv1\aƉo'nWsGkv:Y4Vf NnWc5տ_Wf?؍7]M=rKw:WzM)nW3X=]|gt.D1ݭFj/zܲhљbuGW wcjYUѣm@%=/<)0l#d0QrAUSOey}FMAwiZFXtx͵T kMnW4hhZtҾ0]j2H-t4[xኵQCI²4KM.bkx%ȇ.\< 7;՗+MnWS|꣇ʒ<Sk M Ƈ?gdʵ'BnObwEgz7`銮3D}M8Nݴ/]^>td-3 ToR}w^ظWR* [nu"},Z?"GmQ)u/1>Z$:2}j㋇йi""A:UBج46pt9/Lѹ/22P7of +2ސ9< r7W4wd3dv0+Va]sϕsc7Mk6|t UB m7Ò`ATry{(ZsEn\AGW 2ݮI Oå昧JTOj_ǩ.r8;.1}:OIGKt *It8(.\OY'dv*t }`ZZ2:Tm$ L)nWvkdP]4A  ]_2vSt @fm{ lc%nWCvLV %LEwϢk&\5.^tz7]CĪ:N$%nWG7΋ͻ1SܽH tq }CƔ 3kHTenWod=~)t }dSXR% vZХ%I\/%G6C9&t$Aթ,d_=]B-$/ruUmG,i3%{_?_vr&nWϸAGw"Ѕ%FgKHᴽ+ո]X2vlR7[_u%Cg@GϡJ&AgEjn~6J&ٍWʢ+H-Fr Q'+Huy;J&yݯ^BWkJ-t˫.*Dtz?AהLbZniK@_ZtM 0t)ԮG_KJnWBWB@O EtI$vIt)iƒx ݯBB-}.(dtzrB_EL2ݯ^]A 9dd~t)<9$]Ut)&nt9$M՝ RuG_x[ 9`DnIpƯIi,d)=܆@"t5$գF_~DL2ݯG(mJyu d~~tҖ9kI&yݯ. Q AL t)$sћexx!J]J2ɱ~Ut2 F_ RDWL ݯBNKA=BIn6|"V7 /@ݰ޴E׏(ˉkAdU~Btَ]H2I tzt-DYG_ 2>CבLRݯDӗu d~hDG@_ "H& ݯ. QW[U$tz1DQʠ/ o*GFݰmD(f]?2&tz]@hoy!~d0tz~d~ ]@ ODݰ. o฻~7򘻋|=[{=9RVs_3u9<WQa ,ӗ. 黻NYy}EN_T=~'G@G򹪂S ݊nXC mӈ~kJ'gNMQCU)f֣15uK~<ʶ^{tz4]@2@G;fBcOVjn/ htzuk^|}vPʫ G Utɷ벹X9xog{bgnڎnXNCW|1޳l3knH(L—1s;mFȟ]_Ս PtztXtOt3XOMZ|nl(G7Wy$X*v8Sb( t;Im-K']Q}nXGW|`ÕwLW2 )ţ|fGWԍQt hhݦhM1{GXQC7gKH0ưd5Q7Z@S 5)t cv8]72A ntzt !)7`ćcTݐQ=X>D Ѯ_g@xB5 A5!) ʆDtzV]B$P] A1zY.F> j =l(A7wkHl{f띄YgUtz7]CҦpV@X^MW5tLwF6;QB Q4tPvz5$= PF '#eo ٧˧!C⠢ڋXz."2˜4V:*< +btIw=k}d;  +"Zh9|jɋՌ`2dhv~h^8X3r5EWC,khA#膕p.!hupJQ1x\+ItIˠ6i z->ɑ 莕dusVpyrc%"_C{*2\/:); 莕08pX`(;V2b'5v&acGf\UvWC{Y: E莕+rki~ 篶(nX0.V;AwQ-Dw^2b-auhX@[XgHj=U_v+ntIѨ*ip&>Uz Ź薕B7QNk{H枞>{*-+&G;/SDw:NsO=hIT£.ce\ s6ձ&>,~PP~ cxLvĴ¹$ByM %1w(u$o=ߏ;H $sPx\nYu$)?BgqLC:"g[VFQt 3WP{蛿dO*#B)EnY!o䦔 WPn|-8\S"4B# AdtBW%_)7{[f"_EU5&Aʺu\ρJa{H6W1o:Sө7!`-5&yݑRNܬ/A{hQ]d9#3 }CוB52 Pz!#f_ql܉Gv.L ݑbfgd4)^AHwݯ*Ϡ;R΁y "÷i0 2무9_\a RXl}}~C|%|&9 fIX` KqPtgF[RܴJ9_ܚ_-0L\k35-)∥!$0Z S(AVNtG|<;3YYc 1=]3t_nBwG|}wG gPrw#:/';RPɈos$2G^^EG@IUG4C݃V)58Gߠc}ct p- p^`A;?Gd[ԇ"f/IgޚRL݇Б|-}Чj?c}r3n1Jב 9u9>ͼ'XՑfy nQ)R;HEuҫ9pPib_Z%~In^e^v=K}*ۑCN݈ /f(N%Zm_d9Yޛt!pg*o\_j_> O0n,2"-OQ]ao۹n'?nYfPʻן^;)Y_8C귄ɵ0twCՊRZUE7u>%@'+ҕ$)obHo: Q> 'ҧhUQW fWke6L} U.WL9H jq9)H1˞{eγ:ơwJLWVy?ӑK+'Ip#:8 1Kzv!NBo;'1m\%ZH ʻڧ6]a[^$BGQ#Ox/ SK;{*V;*!Fׄ;v?Pn_ZO3K/G=Zȼ{SsN #or YӪ/Hk.b(T^O9kCa %L$6KYޕXzlੑN tn^,{N2^ky+oFI|)hvec>l5˥ʰ(81MuXhWg6a|',|.LpL(6B#L GWz49)E/BGwWYgRNynvVT`S_+%˭.cPg:D})hT+'GeU o~R~wxszy2aY_g 從DI~8ףģonSiX]5 kϪiG|Gdq1rҏ80:XʭQ8ޭ-o]%ɮ:J8q`{{dl'GQXj=(sOޅ׶vFk:[p^s7pAGI~Yug$Z&>q?95epl#=U|0;h|gDУ"7l:E;GئIC)GV wS} )0ۇv͛ÎZd[^,]#[)AZ tFE7]OxSMWn ߜk[/FGI~H"gϟ;0[|  nS{Qؚ>"ܕ =Y ;7?#;e%/M3C+!z1M6[Vէ>֤5קG֡֍@1Mr<-,z̍|[?<;AEg.!|m~F_cl$iB5JZ/Mo+\!Kr5oS(wTM6=.~}K9&ϣ-Re>mpa; EGIst"o4]GkTcֻҶ٪#o6\AWXTxBEԱGSgCicǿK (Ьת4>W{@Δܲv3ЖOڮGt7/ Y%Z; $>7ʭv;)$ವht7]̷{*P=^A6bIm88-My YfЅ8X J2iغmpVW Oٚ%NO7!ag9:^սHK;|}T-_qJ@GI3LELrU?nXvt,Nh|,:JpEB+].hm5sӅK^+Z (lF)0t;.= OZ.!L[B}SslH 9Cv%'$zd*lVPwyOZڿwEXQ'KȖ& QԍPe ! ŗzGF)/Eس"\_d5KFٮ7W_W).G'+h]*ZCd;rf͍|{)fu3BunѠg7ivj~`0_Mi]&Rqt匱}}wR-f+T_GFguƍCv߿Az?e&%üR7zdqqj#|ٻ󀛊7BIY.k"[ֲ Q%P%~WHvI5S$?kޙ9g̹;g{sP'WL<ڣ@I eZOCЊf?}T9US|Z$|UY.Xfޗžiۇ.RR1xܧ* e.-6zh\j`UNxp͔7_( D vRZVqߟ9mBV:6~k݋?, {=b;##&ӑs:LvsԹF&!_J~Z!]k|碯IXh$)v] rWμUe6~f .4!'x-unLyzvފr2P,HrSM,ɚSgZ|c`w>h(x@`^J=4Cj}4 m6M-zhbGbPm[ S߲3X&ߖBE=4D- 6]qo˄vN$ħξuۑÅF2aIJؖjBg? &tM34`(`[OBXFz(W\NjFPM,UwpOǧ=ޣ.W3e[9/UFYBlߖ|=ꡉ%e/TRڦOa *T[=)-Oyq8-OXN7/>6Jޙ#} /yA/RM,$NI-q?_AYf|,ci89]')^0>إ7.V\8G٫&`E5 ےB_ )!('+YE1WJ}f⸉e-0?إ7E=4w+UFǶiB -:BC乗Лm?~^i3ᲡH%3?/J4X$(c`j >q叧&g]` B5@2- ϿC {w)BK%q*.P`9`Xo7AxASv5-78hsxyNwWy A=uNnͱvΠ>G1K`CKufOSt) mwx`РggſA, G^m7n7$7m:F c^&[^Xzhb |SJb|lzvt+zJ>ps玄*g^S t,jqXѾC8?-zI1 ?WFꑉ+8' YMC%@/2_9{[ ^ێ7>1(2,h`UH%ꑉ 3\ykY~zIt0 PGa~gr??",ᦴ԰2zdbK wux@c7db:v{jXޏ pwPGX?gOb{ trB-5xzGVӨJG2j3&r X攃70I=.qf;::TUU%@O27` {-%x?`n/E{j܉谟 \6P[E񰁮e^}K /%/Ȍ|r\E1@_2ER Pr2.BySL6m/`af0UCy9|B/: fl^16HUހ]NN)z\xq/J}^5?\h@o2ϵʃ"""^*-p8,Xg;`pzTŠ?p?::0EE\ XJq ut`7NKns¡¾ɳ9#;&ok`NJVN >dux`Gb a8ıQ-ԃ6{Zyu7n`o`jז' NkRG0Ռk  S8k@\o 杋с!Qvdojl{`s| ut`~ǥ}${]OzW)f3:.wyMnl(]F:G_ۅz D:#C(feݕD.uXR᡿nmtXCX=CP1pEqG tl"~Qq-]74b&2A}ig^QՅ+좺{0++݁R%7A., 榺OkOB\Ԥx M̍/lvm@6SԤNcǒ=iHbi+Ux3GCy𶗥Vλs YN+/E7'\uZ4u]5|P~/!)j -2YLYw#GSn)Y܍6 6Do2It 3+œ ;j.7]HDo2oJsHY:H0WL|l8@o6֧upOH^եGOn|X0e띿s l]>:n=Ue"_MC'WXGq!%wg=VZ|VQG QFEwr1^ i/]VIlᄉ_Ջ::߈[>]c νH=l :~?{?/i:-Dtl%j/R[B)Vϰٶ"9 hUzi/*6VogJ5^ζVrS8*'j fLˤ`Cm` 0K- sLԘAv'2 6dwJHW\K:|U5F K=$lUm{1X~ԩջ謹Wʧ'yz,ln[,Gfdfu1 7hhb+Ȼο -K\ȝa<+_|`D ;h,vML?r$+g@q>R^<`V|@bj鎍tM WzBcz2utcsH͂{r^*`K,歨kEQ.4fr՘{)>*T'maus$u_`;½fXEvB~yȎy1,7|u, ‚eD!l qUWW4N2}^au'ut+2*kJ¹Z̃Yo'~$N{e>`s**՛SWQ87]LtwJ>j7-:0ok nVO m8`Ct |gZ9ӫл֣j?+SC7ˆ_a8tB[GgTǬ#X]Lf(-I%Qz[DoQtbb}]K͘ی_*JcȻ\іJJ I<tіxSk̗JC7lo'P!j[SګkZ" nXugox#Y눞,Kqt^Pw=փ~珈X::[e,\-:*y+l蒛߉l Ӫs)9}Uxٿ= NNjFgX<?6uNJ*XbGPT^NjArɻ#-=)h"Kԫ-~_FLTdi_TmEd/#Tyh6f\L0 ѳ9xwc-Y#ӬuޢNNY=V q(ݵiBep鍼>'R鄃PT{~󦩲nm~Ȼj%C褣jID|X::Xf0o(\H*:.ܙ<- *ܐ:`}TlIu[~m0XuGbi&38F Qg8wXoLRUOD#=Q'RIQ2+ͻ^>cMm˄! Tf]@G2@eL_#G%KRq@S ܣN mgw* MP Tuœ\$mA?hp x:Fd utV~ToX^u}\lmI^ƺ*ט}I І::l6l׷^2m Q J׌4FdA_Уw2s-}<2\[Q4ua?]To:Cȳ?VD$^6~mi%W -2Q:8{(aɩg\~V:JSGgV SC""J-zҼ$M F^}ΛyXy?B.OAK^=&Z !lMYK6QPGgߌUϦ{0m>Y,{:k$Xg  gp2Y$&Fl# 8I[l /7D[gb6^-=O3";ICŝj-e11F`!jWD#üЊ::oD /+ψݗvի0t0+1l].3/-]knb:V.~K.Bϲ252 W3LGKzS@m@-%61b`3:׭i\%u fZd[bҪ#yp$m 2h4eL'RgXzH/̅w nb:o,_wʸ:gUZFKj NܽL 7eb:u5V+{ƕ7wL9N<ɰ}7`ɮ\-FO'̟A 'K[®f8dU7xHN̚>7]/cзܗy5G6k>q]U-FcG<}ݛfIԻA ; nŔŧ?Jv32n`ױ Xڂ:k]cEX:8~q%F lTg:n?NBwᠹBxaE־ ehK܇!,fzk B#oeg׏64y > $=YN JKx߰j[(b#G)󜿤/R%E٠|O5yE0#"&3O[[ȁuz,_qwOpցڰA o1/rhKMXK1}O|B;`"zFFL8R /ZZcanJ'F^CBD=}OL'M62z`<WPwт!D+xs-qWV_ :l)6o!'GQ*}k-22|`W5V K_5XF48B6<o?з[zmh^S' ۄbٰ~aP<눚 U[Jbd6h^݃#wB4pzMF$ Ļ)KXKpK8 zxč>/ҁqu t/#N𰓊 7ehKMXgCnã((A/eE[ab:=t/[cԝs@/Jۄ$# )uC/Ux)ގ;Y,?~7w@G^1 +=2}d4/gYab:Ω 'O1_lXȈ1-pK &vtk/qmx,tpzpL VDVhPn`\:+ jNOfk}S */sUE[1bϪR=ʘ_QO̸:/,~["^&˄:~vh,8NY~*Z UŊwZ+^x+!<-X ҿUcx}Y3.EUpCIJ ,api:ঞ |1ɗz%]Y1\L[^L /y[n9!Col8x lڸ4!}W"6NV\\8l,-(|zNc4'ig)=f=rQ%s%6&9,Y/5J[{4ot״1^WKh:5T\RXqH|J\ppKYM *hXN!9.35T;nn`Zwl6 c=]PN~}̣e!{긠*J/HM;d䯩pK]Y6PwS vб vp=qɖEwta<Ζ?DQtԽT 5lk:'ˉ. cf/"T^؏$xS j|c]g\gҡ&tVO(dPgū" Lg c[Q}WۦbSX+w٢TK5Uz%qUJh wD*Wo9*zl@chvz-)׌+5Tz%aW))]KYCǜ{Z%"jj,@7NdAh&ƅҩJ/.]X63~ 4Fo!k,_Sx9:֩1.UueǏ>t۱@C~V?ȟK~b\fˈ{4*Wʧm|M0RR`|7O;y;ߣZW>22OpSKnojx <_{PV댟\N)UT hP3{śl:CKP?k̸gNdOyM1RS`}?GyȶFѥb\䜢k[R@AL &j KWVB53K!w)R5+o䌢Fqۧv)BH%3t2H᭝:.R#e֙tGf+r >B~0fndx9ոLU+Sqq T3tDY}Vb2) 7(8O&Π@os )=Mb{=7eU\qF R@ɜD)s!pdp#9u̚U?tbߊl#FFJ S\CV0vOr|'h|򊟄 Y-@ uەS-椓EXOMo^T|uzM 3M=f>ԗ;y;e\ܬh<"g,_o-#yA}ٖ$Ɵ//1-U9c]X ܼ)Fƶ`} 3&y;BR:a.HЁ_$/zd>=<=p.ni-9Pل[m>\=[(y6ȤM/7X3''|jpڒ>CTJWbՒB1FJX]'9`5WX0?tGFJ]N0SV&`_}EMGzF[nvi$/Uu*3^h:(0J+6=uw(U2FU'B:E]m<N~VZRw?,fQ։ /ԧ lʂ //fW~!%SW&`HmΘoe`V* {DHys_[!5ԕ ҁ3ś:R fN ]Xp;'tCp+0yoԣ`uu_ȽOpwc4{U]' ,+% XUu庂/u1ZA5 DDuRP@go*_诠PeNjy^qPF{GwBF@w|}R^_*N+uhm第VY['WT݅?كx[9X]^u}Oo憾'mF2Z{Sq+ 53ȏ7%_R{3ˌT|YAn#Twr)VkQ[_=|Y9έ:/X z}9tc ,Xg4G6 2EZs?7jƚ++!!{:h(]Rw6*}7q^)ߗ!sCpRlMJrrT5,ױZJGNzuQ[e_@P:fXDg1]ia"(ej]dŵuтG9=]&𵳘қRtNV2ry'[a_R ^ C̏=?e,By[֙ɧ|5{ .z=:p-ImO6 9bI6YLtwȽzmߓP^ + u|@@nҩuՇv/Z,xWWUe2izdx?J^_K 'UWWA>x[u (&T0t{[:֑?Uk*Nx[ms6Te҈W-G M)ڄtx3 ku'M.!_`f WVNRK#>ʁ0qZEy}O Oۭ"c!kd>:;&їw;\AyM5*Rq^0CP^C_l5gGBbԽ4g Xe,u:X- VHpl_ISbBDe5Voݼ^?/E׎hQQ%6ڵLPbQ"}ZV[@3UT5bpyL"UWBv=Ϛ o':,+u**K0L:^9COjLkʯư7T8›LQYu?yKDZBN!=MrQ ]x:Yꗝ޼i_ً9LvH)`VW*Ο$<hԝS^Ozfq(ev/rU*q:Ug4۩JԽE?Rԫ?m@ z.vMms~(xUr[$GEF t?Wg6XU:U驸ۣ =I9^F41&ʝxml->=vCu5=vgxla׎z2鴒:U骹QwCR"X;Ɨem| NOg,mEgu׼ST~>]gGJ .?M.&@V{:|GlqڪvceSۇy{ԟn#fϤ]Ns~}i_u i:ԝoB359~JifE.+*\vD3:YKtXyDe_-]sk42_܏ʟG=~:}TUVk=M=xod,C:+SMԔǚ%׋׷żN?o`\GFpۘje}Hrn"RC>zw8Ko u=}tQ6p\騊غG`̈́MRzYޤck?cHl &ABFL?P xשuefPϱ&JǔT ڸxuk?s~˄Po5uɭc&HK&}yY혆8ml|33UH<gL`'X#M̫lkyv ͼc6G| ^_ `=<ЩXYm ư=' 'B! +)amCFgFFu/KgJ3GuΤ vF&uV/ݥq $5ޑR{OO]q V=tT}b@JQKk.|sf+o`>qAV#=Cc/\(3~!p.ŧztahq%OC啦^߈HX;{snc)5"ШYB /OQ4MmH`-+r= KYXBo7+7PgB^n܃2h;f/['{#hAEwzf1'FZI6Pkj Wo2,W1{Qڬˬ\!LܥwxB Kk<2Yj?QXʌV^nïP\agu `ғ&bebp3F' vHY[ '{d6f}H~u8>oYfXR 8TBqUk78lӛC2EQ$]4/T=;nk#@fXjv]8s͊A1kbr2IKCtEѺ 9HuJv9`C_Eˎk2t^~a>iIKi >6 mY3X'(j{]"/R\|V:i)kv" ?-mJ& B:ࣟm2IKo1?Q;7B#esMI+)O/~GR0Gf4tow6]T։Osf_u+tW;w;u_yd'-Mg4VOk8nY1/5? ɼ.|=غ'4y5RMqGpʧL=w={TXl¶? MXϏ;݆Rz!wiZʫݕ4;ō*`:|AUQgOPm ]B~φ9,*QgO\ ڳ3['OMmrY[CG2F2 '>]Ws!#oղ# '03Y[nIHdŏ_'>hUղZ;Ș|zYcCM=GPKLڻfdz\+|~9g}.u3O|'Rrk;UD{YU(TCu=,_18ke1pp+Iw/WEɛ^vXSȭyoh\ ac#mLtF+Q{!SGOiۜ6DGJ;fBa9uy0q~iq ~UVPtQaT`ZR@g4M= ]kX1ߘnmzɋ f'mBD?gNhG):ZNnh0pR W9oAySz|q%3^r,Olˮ]I}+ّ&wnt"RGps~d.#s%' \pn<sǗ=Y _8?qe]z(~opZ-70GUb[u4M=.~\CNK=5TPm 7~gTzZ2/vl"mU7zTe>@Pt m3o4EO $ܫ2 PAy6Z9nҏpG qu53G-Ξ3wWͧ7i KPży㡺0oxX.7w0qtu>s&xc*'"3GUڊ/,.u}vu_u/* RrI [48a'S 0oE2Wǡr=sEU@4&PwL#E Զ7?]C;? }K&xL5c 8[O@ZR s@hN'x&Տ< &u)Q™#O 6R _pp:ѐ܂GyHK^&u! ƉUsI+xG)<`3R?Ϙ%MS"M#P:Z@h։.SCNnxW C.GGqxY@1SGGGu@ߡihUgǏ2ߊϢ""ⲳWR!Q7ލ^%pG qa/|D)HN n#WEON9? wջ=$8# Iÿ-'~ŷt1}8aoF ,Yv77"|' n[*}:Nƙt†zsiƫɩ80t]\{W 3[KT+qߪO<㹥@"A߯Pwxg@e"S =~j  (za1ώ'rYBz ayx =SEqݶ5 *佃/ߒzwMK͡܋/F>VK]{n+<9ض &8[z^*WW:slzOzJmԙ3Epx2|c8)+O=aIJXCYtg|֓:mN8RAըNuOA={ lT`5m ;INcf+8 h䝿jv $Gq7GW<$Խ7;}TiCcP"r|s3u@ MKUPk )4_nz 9{<155u@|*h=|ټ3ŖWw t5WYr u_L䐙;.{;u'ƚs~TGSG?z-uU+š8*4oYvCϧOzB6c2&~ށ$mzV Mbw_BV{g}[Ggxim)O{|`3CiNН:J*5ig\ 0Ut_:`ZNv7M^-޾;w/>q99>%ȐWueΜF{k!AmPY%!uHU~,]a١ ,v>_%zc9H3A3gD.e~^֝P}Z8jQmvz^J/RTګI:Jzӏ?,狢[7s*e s F5t+UqWg+owz=^ _Mu"$e٨Z:RIJ3V־4 תW5} +AxC>q˝JaSz +_.g.܅:m_3NՓ Uj!߸0u<8f(@f~%''"{?"v&{D!}S.3f41/0<;vـt},VJsm $GuK{}3_>S6uUV`'aJ&pef(`Dnymaؤ5uJ6\UAHo 7(߳uݟBWaQ7<6vԷF 䦗<9++u& ?졛z/5Gtm@87sŠ0(ڨ% &@r,Exa3SH,ԩŒ $3uL  $˯AʾsCsU1dtccK/*SjyI3qo5H j hz(KI&Aoe|A<&K7h'ӈKSD|~W #2VWYjMRV WzGhvP}/!}^|y~jgϞo EO!Iu5APWT}%J^k\]٢'w\$u[#naݴv:ƲQ3܍ d܆z+ym@/JO~4zKH>K:6)<璽ح$J2j S(%&g#X B%$S>԰M*Iv"0$45x]da%ad3AvEu`&nputJrN(ﴊtca$ @}nɟS۫l@]Wa\ISr2w&4OtOZ7>9;3(OQ[X7bNjV)HyJna헏C^N8>5qdx>}aEr $NQa=  0O7q&g $X7y;)d%qY $Zo8S1|"G{9eȡ'7͙Jy^Y;"&(@.@) 4 ,@kJT"RQH ~#@%R@LSȿSIQH\u xNH/Խso}b7f.kxo\:j1L75䐏%k'@;m3- 9?6S /E$H̒@ޒL:,L1Ja9Lމ Д}<-HߍPKⒽ@ZfSR˹v3~O B,,俁W J^''dKԽrc% D7m镼b>Qz R?; UQwK\:'@:Fa࿔ Fa,HzK],L=RH]hA[o ԏ c]Za,~i5Fa0IHtR4TaZuk|ւ+ڞeM ܲj-[4 u3Y D[ ||h{K헻zKvS.5T,_IG[.7zXɽ&ޘ@xlv(:f+6M >c#@?rUݥnH.ov\R X?V3Mu,<3G:ڏy9l@ Gu!n#ޘ@""6+y6_T%??G2kGlABHDup^89;]b,@TAM+HDļMd*@ēXBGPQi%-l"r  qY}_%RA]˽w`qX4m9I)56},w&J͐$6u%1Ȟ$\Ԯ KP3~-7gQRtqx:I3X4sxcA4\+pM2b{*|l r<_ﮬ#M //3Bg`,ד^QgoO9;1oz1@K+i;ޝ@"JXc5mr3w8B_a7< 돇'{$[x3g?@Z놗'w󎳪8X0:JQbA1 *6PDA,IDTI`,]Qc%Qc P{g4*FbA#FH4D ޻sgڙμs G^z.~eD! NJX9#}5yC…`r5Ƿy|LEWGΦR|Uy[8s6A Ha[SA^ޠ Ϋ&o"9&j- vt%0$Mn"l)]4y4[ HOn1ȩ)6ME- nӫaۭ5s>kQ#g\@NO>j.:'nbyBbYp_$o'@A]Z~ V3jA #4.tOJN7#WE] @@ggq[MoIopgNxcņ!l"㰞ےٝDƩl49O. Kn%V],Y>ζrޒZ:(m`wqhפ-%û~F`wBR8LiUb;?iaGԝ:/ 8r~u.̽%'X.roTB KY66NYhXUNw1c|}G(t5 Bk{(p_4X ׋I _6(bY"4p7`~;s]@7K2Nb&fgH i抰2\Nt2z:o_瑩d 8"߀{*m̨ұ"81rZD! {wD|P= )nj. 7t#*KoGzu '-f7M- $";5廵+,M]L|ri->Z{E! {of)-@*w  ^.lj~ys)UAr;-Tn ;hh;SjiE4N(Vْ}|RXM;)E6kYA4Cqk7uC@`$T_J@|n?Nñ{?$_#J]I KTfM$>ܢ2|R -'ؼD!hX>[R m+)\NVMs a]$I5I|y+c ojZ@z66|ेhH1=,&EI"{uP CW_5!,x2LaHeIВ>*N aB5̩\Hh%2^s77d,ڼ Sn\; G0{9 . ˒eW`2*+| "6K h@ ˳|w yU-6= \J>{Nn]E@fRj@=X~6+| ?[l-ti 2DoRϯ`ǽy%tᇺ-A7G8ޱ\HW $"RSEW>`Sɫ5$&ӟf:{@|^g Gۏh3aV@W $3 pRhd&hʇyof y\dij8 D# hߟypXllyGVWA>y^iu=mU@@)̙YfD# 赙yp C)3.anކ #sje6}8)RM}@hhR7t.CcM-<3[|C<шa&s|NRIZ*@@^e DÏq]4Ym0X7^*EC>\!J[T2E.QP P[yPKQtⲵW<KdY7Ъϲʒ7j>\!Auުx؇Z# KR4"ҁFa !EikxE~n * aeE.`F#THmNO5`}3"Nd2bW7"ӏR`VVA^\!bV( ݺE0abmQ$sX)lT$Y-ck v /M"ʇ1A Ⱥd>΍sv G;1+澋尶1uuH@ PV >cfUjg <r[o*Nq$fU4b+JXEXoFc]13?.j8QÐɋ]}!@O34}0p][xL5#uҏrXS 1SqQef4%^gR7*EE P@zُC۳7u^!*!7?9(9KLA"}UkLk♶dWv,'uV>#I/U_p'MvR/OǛ,d3۾lO&*AMI ( 64U$oDBN3Li Գqz˲+GᓉJ@PH>*C#8J⃗ >`Fm;_1Ծ{E"`WS k韜n 9]Y BTҎxǓ B>{GDxr|BhGͬ{W""!YCN~:xd 2fh+ u'vt}O2?l{WMDBb27:ȏrGD'2]OPYT) + Vϑ$ G|>5>K,{WMDBf׏rPJLV"rɆh4=B[]'Q@ H8lHޣ-WMDB27*]u@H$`Q&>yBT zڒf"yCہV(w]H@HCƹ? O@H5׬r"[YIhTTGO@#= Ƙ&oh h4|kjMс%ZC"$)_ӃAJeZ@W/u4kUo"&0LGg oӽ". ǑU/-Ǜd;nN'*q5 [m?HNd o"bOXG\VxE/lQ,Z@@En61I@PBuli2O@iD$ $= kА/o-^34e,9+L#|xAwpƠl{7qDG)Sa~ U='X,TW# iFlSªãȖŶLq?zЕ=XOAH|* nƃay M}+dck>LQ ㎄5j+/W3N$$ }@%K7[IH@H.|,7]@@y J@~@<=bF$ _L7z$oD:jFOtVL1DBr;e,wG4n&Q )QL 뚥~3w|&_F4pH@ȹM~ 2a' [:ʲ.64ϖoe vSϯpdK0áѝǫKDBޚEcYG)tA_-Ffw`|gȺ_OdὀwWxuQzWM?C@Ho+$ du&h3-86pF]ea$&`wThL<,RFͿ;ƚ#[,DBNcσ~ي7pPD0Bmac]Klx@PmNl9Ⴡ xGη D!A!m;wW YPZHOV[{ųifNKu"ԏ(+gdL )$&|0U8%^ cCف(YM<B ~nkT <+=2>;C،†LfrmY11ihkL$gD<BbN&>k *3ibfă4`4b#zP_ϯ@dDAlZI@H? 12Ya<vX4ƲHO[sU38ڰ D@ȁچ{Q/6jLBg`A9h3QڞE#b$ )6 # $,cc>C3Eiae$ $p΃&! eYIVūJX A+ %s)iEh-&&A0+켽He J$yL{IpI) D# tGw"b#>v Ya<7"ķb^F# ˈ_ D+^ 'DBëN:qF@PYF>܆fC:JQCbʈH@PhH.z*r';+AtE1?p4.ʲ2 pP:9eD$ (%T2yMNLOJe A@H-lM-tAjIz!7 wqaR"?9k]\|5ir%t,kmb)Zj F?tg aB3%I6H-HBbxќ_BU%d 9;`Tf1gMiܙA Iqh@:û[mty26"!1'9'g6y@P֌6PO(0.<ԘX<(M˗-Ve9B6$ifmt5؎˱$9@q5E_ {҃ռf;trI5@?*^ ]@H%Ku} bjN)X}u?m/ 0+{1m{𱚦) #:z{h󺍕l@B[àz $+>G" ǡ߂zMнri 'UwyW;֑]$m>sMғ.&v"\<>|AAX١3{y&aW (^R,<1y H[pҋKjH0|bPHB}ip(3zpہkxYR0+,Z,%oYh*2nNtaOI1 rY]fH3kF,TNIa li`/V~&gHޜ8R/|D3Ӆԧ؁tԿvwEbU Utd5$hŕHr%䌘be5뒳gӅF$o|id@ , T${oh}R?FH6)V9 \tu;[$EE *W83>wd5M %4K)}gVHAtcRtL|%0zfhBr(85uf]ZJs{;YMS܁ps`3eW#49SW@'?+"-% -KU]PSp.Ah?qQ/lk'kp,ifK`sI-LcgIW^F?Y+1̀gsv(k|[싦- ·jW^Vn%vlEOPxVM45r\\0xpPU5;Kt"Lev뢘;д0Ì;YCaJLv6NPm =gK[£SV֤  S=t,:-+2Ï6=?eAQ"D3^Ћcdwrd+")ABbݎUUB5:)ژw՝-pObx':YN=ZK(Z@F GXВT,eW8Q <)yUKYE1 ) Ҏ:sQ@v"^h\X5C#؁tb+j.}BO f;ܭ4#,%d T$:%rM)Z3lC#XR\t(dwKvYDA۹pR=D+P# r*h&ZAPy6N &,D-u褔p1jZW~V@W%:TOJ~{>O@Hpfqp灌 ֕PMs磔OhQR$oS;¢dMd35l5O@#wO7 }%3A| w^ uĉhx TĎ^zh`t89KX]"7!GOI6E4=xaPr<{—X{*\ H ZY&;&{m~'g VL7l;0prjO<.Xh+0޶bwBwkhȫз尔:RhĐuՎ3%G_؆Cl-o~;S$E!jK Ȗkh<犊K?.q5$פI pVWJQ3)RE< pr % gqSBIW)c. !nP?D`\n`j8<&u(*,J  HVf"5>#OZȃx Z_ב"Bcjڧ ObO &bok$ w75pl};7# kJLXQ"H`)ДpJy{>v# a+r]w?h#] tϰnЖ%A_a| a}NVv^'PXdi=Z31hַx%hP_Q5zё54#a$vQn{r+ &Z䥔EG@HqOͬe Nes jS8T]_? W݁hTّwZ} :HrAl| _8歈&rq")%?^bz~! bKfkԭ#+  tq.£89.Dzb+ek9TWD$JS>Xts]kZ6yinA!KF* #u¢euo3b$WmKD']/y|J2E&rgަjc+}Ukh? ܻeo ƕ|iKۍ9D+Xbx}hRn1jr+Z8EzyJL4:vY[bSKE=)\ED{k?b[G\L|ʐR2 %H|6H/z^|,;J_UDpjZ̴s5M@@QB *zK_z'Fj/ dUWfkd\X7YlZJ.6]L7♀>_y  EDK=y d>PNRdıZÐ"Oy }ޢWx v/y68ToKSv&K6uA:Fi!uczwF|fA.я\=V)ң]CS?*ui qu@I\$^\ڐsϛ[@P%){ Oi溒~_b6ij>DS?]SN6&;%,rkcЌo-qOT*n5uйQ+yG:}ER&j~v z{m2z=xHBަbqa h]% l }^PXa/K%ZyHMTX#,}[46 I71}|&jz _:g ]U|_2tbqޖOLG, ;Id4͆hPЧu1+/2\TD}GP]}WaKȬf UXA[+ |b/Щֶm5ѫs}:y&:&h19(O?:%Cg;t6 H3Wi><*Fgy=l߀?)7WNb꒻#,wvcDL &sz{up@Pj{|hFEa|F:jU^N*r |p /VV!j^ 6z3`qmx 0Rkci!B؁ِ)ZE.15 יF`!V5?2F[r؊l-U31-|ƧYԞk<|2!6?6ԐY{d42%Xte@3dȯoiR/ϐN@vQłUv֔b-?zá8 ȌMuCwLwi ˉЋL<4lBE`所 {k[$Z}yM>$#iAޛD+{ڜXZwaS[%-I*dOA(t+@%.x^Jyc[[^zN/\AߍYZv3F|x n̶HH)(۫}b.`X!x+;۫p \_*Y4fjd6R1rXpU."CA}P-7AWB/AuxԛC1$cuv~yɽk_ މ[@~7BH^#fڬp):s% wd?cQF.c҅0YB~D}G2o ˬՙ 㝬Je`q @oq\Vx25y#͘ӵM[B;gJ!.- E@~H5K <,0Ӷߙ?oTbtE XT5ηWa\Xϯ/ZՁVoEAGUZ{y5 Kli^9c`QCJ#ycYkLr @k+jל3oiQ]B5D* HȖȃ-tpsSX+KK]c-E g1z\u~ޮ'uꀢ*x\~]g( #H]]o2Qa) s<&7qnw2bd 4#eW4D@ޜkcaamBLҏE@l ~maQJq- !8\cƞ@}eu;@?30! 9 36 j2pϻa9D_~{jwbݾ1=uHsАd3 ۫p\@@ Pjdt*c^ HkԸùaB58Tlo 2yV'&e ]@e3|%bN(bZdw!7 \@L0ZlTE|'l[Y>l 83b~ev?:J3!G~je} ! ulu|-B d}MU ׀顽0,ovL.qۍtAչ#ũ+ G>2~y;9Ϡ0&#y^f5RgeZ U@*/; KׄjuሼNb]y_:t<2Ly]yՒ C*P;fdx@ rJ"yXjjs¿}Nq9ӟz;XQZu) Cgiy|Ԓ,2Y€z%1g{Y'6Ġ>7v 筥Qϩ,/- ~<º ;ǪYl͞@fQv 3SX1vSr85?$͋,&vuS!.w i 2$ Ne -p~^ \ٽ;w*7x GX=^)yc>С|f}3Wx'\ GX̹K!63Gdz^ %crOhsMohf S-Nv'`¸5M&iG9r%8.wOҹ}w|?7䄃7>i/k Rm-~ suZMo`Jzf/@B-or^8[gvFzȥ{寮k5˲ߵWuʮ1`WiN7 ]FK1rf[I,꣑Qz$3̚)-/]r-4!q8tU/;#/r>aI]6{/it[լf5MG3-;%qg|ۻY.G_s^f]v:?U8Øլf5qEM?ԇ:6ݺw>An_w[VKFGEJ(J7l dˤyV`S;IDATxISP\^RH @P & *"V:X.ZW )ga]:8 %yWQY(L-,)Jt>O0P`+}~噞\hx<ſ4Ms\.!ˉ<΋QP`M'aCuK~mN,r$Tz a `",=JQ!-؎%fV5" PPS~[@v^u.F0|a𡤍6-aGLQx#A߸> =ܤbŶt8V^jS\?#9GxLS^>MAXZ`(D Bg/C>O jY_,߂MdFwK;3<\~/}|wZ-c#b,!vR=Ȣb/6j~5P ׺MLG#l~q/)/qyRF(]wR1\o/V'`y$.tRvqt9.MY=oUc{}+I纏#\沄87k>Ss ٹ-`VM8QT5<8 ʨ vT| զn19)ލoDD8Yݧl-I> M@ h2g’9`QAiѿ@n1$%LX:=cyl" \%qb>)TXc(u-nZavͻ牏Nq%;1lIuX8(7 +̃mn `lG l_{G belӺqp鼚UDE7 ['1ol1ج@µE\?AyaR|z~ƚ5L ú1-ߒH~r\Ū%κXuDI>`'63(2fY,Iux[>$7)b8VQ9l_FKwP MW<# \? mR,x8@R ] )/Hh 0*ػ4(fLFKiM:4IIkɌ^A_j ]xCLD?`fXd*MX#.4=?a܋ b#`%  3AOy3aADsXQR!'/ ]7RP'3}BUޥoHP~5e=b6*C ࠽`c8E6?p`#+BEV )bgj@C3wzhF;(7?4cv?p"^%Ά`E#6HR@jO?x`P`νZC(PfD)h]B o~Sd ׿u3"郼L7*mV ur=V[ Joߜ@ƕ@@gEJ D1PlՊG ,ez)|ez8TnuߣQwSV5 7چJB4HK@|FT> lyΜs8@k"0ZusNWil;QlH@[>kc2~lyvc7NWfy `qsw+,L0n3e|U>>H{!/O&^%Of1c*`q_T>Pط7nkV|O0.{xfߕ} @,:YK`hG0Tl[>rǑ]Ha:|#Fgv|Xm@ПJ ջ?/JRBHh[sHHGt;@E_S?08T}3~BccS}xO0Xxi@K&;J dz"}t]" XÝ)rf-@Hb+myM ֿ UCnt,9Zv q0pZ"ܫpup<*MK2isVPB 5_&^kxuWs3e>iA&.İv"}{'oM(ɁW Bkj͵WWM1inyœHsk{ŌDznW2\+ٺ<ҜOYLyf2 )CXK+9h=%v`K`_E/0h6`SکMEO?Kw 8KZU`Q<̑#(?RA 0Ci|[BZ{2:ZѾ|X?[`KnX4gbkFVt[s]-S. `x{,i:3/ *)j8#ג_HДdtiT%MK'.f3ze%:JHmbf: &'5 &tUj/)(xm ſmL?LPl;ǤU@,"v2+OX0*f"(u:괌 %_ .3n6in~//hQ 8=!'U>w?-QQO gQ4o1`&6E t#AJLpɲtBYse;@vhG 7#Bsy~>w韽h:/̽PBݣ:{kYzQ X(z*@;-7eÃ@킬!K Gl=<KEf^%Tmq鷿h}*Phh׌`( -wV@*~xB U(-Z@|-C@Žbdx+t[ Z4#<7x3J&oC({AmZ?${1߿h -%+n!4*JpS`tE;#((!4&90:(wCaJ PwU5&qxd}|Fm|4H9;/T`'5 @O N('Ҵ{+" 5G JQ胬gI^~MݕVs@GfCp+19 'ܸPбfI[4 H*-:>x L7m_S<&lcdK͵$e =.հp3 ~y=g@}O@ya-nZ O@mK ptKۘ@LvQ I%0WD;=+,Є19" 8bT[ Mv71mRm„௶yޝqD6:ڷvElc%}b%D1^Z!xw瞹͟&m3<~<9!-gʹE = ⳉ t4fnMb0 rL|U@k/STbo0 ixhre9 ~qPu.z`W ?p@fiq.4FՋ_ g@QM@^9p o@'iƾd8!r@|Q@J@&ߞcmHeIQ!fR$F$ u> ŘzJxfx e,ρYm=6M@d5||=0"]+Zk 0 ȡ|0c@'*^5u-^5u,; 2Хʸ< 6Q`DS}`YFR ΋\<- "+#ѱڤ^݀hr@SI2b{  }[(^n F/3P'~P%RmS q/q@0m 8 `P8gإ_\6ZB) XϹߴ}jǯ*MgR1 \|J1leDDa\ xa[Y~NoBT{!]or0)zo?%y@)5)G, (ڂ| !&P֋eN8JtB_6`g%$+U dMȽjq&Xl1Kq- ,Zj!PvKGVYr#(nefyRXKwѠ70B5= ; @EsLWo9FW60` 0D9|pɆ`ٍ^İ!L,(g sr[, Sd @7< *Ct]t}% ltc , + q@5X@bk 4I@djhXmĝ`wcK2?,Rbis"{A9 dR6 l'+X_%.'4x]+ed%HtC~C o5 H1 \mDfzLr'6d̐h* aC}8DSQ@t0:@)\6=4*oU=(۬5@td5rC􏽻i*0&4- UA X~)F"Li 0px? ΗEڥ-8 UGPZ.+&cyV@y71aBj4@PgO*u*{3F2l'uP}c$TR ;S {1GS1;&.c%fclo56,(tct7f \M0@jǠϭ L0@ qHl'%Wct{=0{=HBc(<" wQck hעe`"+QI`"QM@ 2 D~7\t"w@>rs Dw"w!$c\{; <FnA@*#w`@A@?*ߛ*ݳsnd~tL' PiuC2َLI`*^dL PG/'AmLDfU2!ي {Ym*0ִ/"Pm!hmER8(XAUxv oP;[HnK9lY=g&pS G.T,7OOT щ 73gB40/q;< ͅݝ1 p3L ps n:oPAfvn7 p3 QyʠJ.n&j!jHbVO5D56 BOiAJ^ /@{¡e ?F84 @ D"B5M9}!Bx!@w2d(jmd>uZyb/dg !~7@; HD|  HD~#ͯB-[o @Yh@0hi HD|\3d ON9 ւ' R|!9 I@#96@kcR)橄躡 on3pePk QC8Y&) O5D& E%/ @kPP=Br-@I{K="% _m%0*63QؔݴIԂ4lmiE uAaAt rgךp/ezc?jlV4T-ъډ%"$X#\; I\B993W!399ǿ# @4ߕ; ~)(#@=R @>)ѬH"]U MKh;^24an3бVJI{aVT$N*P% 85IBd$!)X+!vE p@HHVE Q,C7|d*A] @9*;Aw#\a ;R@~MۢN kmS$PګL@+QzJFVSseHqVSsG2 ν@l2#Νg(Ê,`s(LI>Vs+q\ @|+U&m*%0eMܣ"|WXf͑M(ۅ uK[#(i` 0(P%8vmCgeGA|{$I8 E\|&mM c6阤 RDʰeڦaM"]@[X:+k2-8#9am6L2"xV{iqa dm5G0 b8CD<{(EFqA3Fl{%aZnN0 dZV~NF_dWb k Iɳa"8Q Ka@{ehd ~ f]L&+_W4uIj5rL\C"F,G[%[SU/\F KŊV*}Vk%/%( *AKg&gLS̩QR>I(> ɒ&B骮﮿%)]59[Κ>{ÇY/ @{9Ѩ=vhEz/F/ #f8W&GE>ЂSNJr1i?a_v-;~&:%Kگ]NK'TWE)|M, Nm\vL}{"x{\4@/W!vD7s]"`ÆD` ZfN:` Z(L8XC \d0@+ ZcEf 9R@)( *3@Z(D҂@'( UL!kZCbxܸQ);XBrRr@UVb̿AM!x& !Иz-1- Ɏ0K7$kv(+ۃ>3J_< L+7VA-7.!T;XA5 bfx{+A `Ff*W$aXAkYZwGi(r|V;@oK),9@৺*?% 1 ^E91`xoӆG m@|$aZ@!)wḤ`< JpK#̎tH@g r$vH障:GQINF(;i*0nڦi M[bĪ &F^2( 2g=ėY/pX(Y6+rb!Hwrځ@ ͷ@OsO KwJr;26$OY O$WsU %_k| ]%9pC&9ۙWx!H^x<^)֛V_ OI@l# @Xl*|xG3 bpAΔ;@>'VDݏbf IuCR0 ^`@( P q<LB s(1WL" `ޒ8XEczN<4h`̵. GU_۟d `Ă( D7> D~' 3q0C0A=VX!QZά qw̵`3ê⯱0B0&8j+l )J*6 IZ&.|@l.M>@,u.[ݲm {^6Ap$Q3U G&μ30@p}$9az~ 0j[#oq_ßGp\³7 P{tp "s,D""#*]5kYZ#V񹣻{ޯ?sw~\s }" j/b3-t%T^`[ VI '?کPxC+ޒ>?Ge \\ 0P0? /8L+ ; "`UQ-XBk"`Tl ~[|Sp<10)]N^rXtO8)\"Jn+"܈Fg\_K`͇`r^A 0fi?'+\!܉Я G-HG},`J᭤@g)qNT* G~8qD0%x@'O'or/`hN`UIJgG"`< F_&6365Ά]"&T%I ~2܈ml@0v$6@& }$Η@]I= ΀ni,I+]X uϫ͏$n; i>7{1yE ?`#p^ e7(q1pN e_ٻݤ(sS)"-9-Zb!h#IQ<K iZ0{fW|o X46xY,M'&(=/h/[amxr@ %[Pꍂ5Iu) 0< *wL Mhn u$BJg2;O ;Z#|0;c`@/&hxf'׍["ʴu?Y8" վJgu&ų^/Z 0-;BGf5VFuqXq1fsĕ̀F3DT6aܴXRޱGTh}5"Ѐ ,JN[" + `':.YESpV.kC"e*<\(CDStdG>VxF><6p.@6 8 RPy?^2?| xB(Kæy8)6p 0: Mt޾ 48 Rq;gZ_/o@=)5 H?ތw #bG' F^}8Y!V. cADȍ:UxDDȟnx  @fpN^?w{{V`xn6 #'AJkmj5RVQ>7M5k!}5@9әKFc]7:V4b@dg`h5 @J/2,;X*,3BUeϝXjG4F@dų(3m4i|@Sۜ:uo? &ϟLl 0-yTx|FȒx{0 J?߆K1 |7ў  G?"":HĘ_A4;_R_#8Ṟ̏/t B滁(ߢB$_]@6Kr3xW`OšoYF3xt/xah>DIjx@PM O+Rf ;J?,>SS&NAuQ/hY%V:jH Uj*N*n/le] Q l'F*g`x%8HKp=Լx3x NxkSaOJ  ש ~n8-1PT>.Xa@AWLUݟz.`QR xESܻ2Ay@`KXFHVFh6+*D%4`A~)<-@&.Y3'N.%VpWFlq_d) 8j aE$!& @,ŔL4\s;GKe,z{t uIN"oE9hQ1e|$I.]Oo2 61Zfq^T*@m~^i X?rzzAvn`/ F&㭽`_גRa`F#[ o$㳲` G~`8VUMM8Ba4tXљ:~0@Fe\x H)6 1c1b@0 +叉к0<+6v9. vasEZ,}vK=% #X]]<7 DWu;<11-[O֫.`z֖_Ӧ)O$/a\2NXqevs}/V1U9a^ZyCh5_%Eu]U*k!3 \.o6zxyt x  Yy~p-$E@ yp;>u.:z|~mNXitw{76.&g4?5?4GDB_ho`:smNɨ"j @DS&C惘yۮa kqnΦJ{f]| e ?4 Q n^! }1#{\ Y)bB cEw<X A`xmGZBKL%x{c2UD]4NIENDB`pydantic-pydantic-ba0aa01/docs/logos/github_logo.png000066400000000000000000000152701517143232300226760ustar00rootroot00000000000000PNG  IHDRæ$PLTE#" % "##"#####"##$#"###""##"#### ##$##"##!"#"#"##"#####D56tRNS yU+̘f06bDP]!؜%YLnsjI:?Z뛮IDATx݉r@RUxD]x$6U[[5 fX L@}t[`3n;}o~}= ^[G`K.i%&eiIO0^2~FӢX-MgEQkXmc]t,~y# +*+6_& DKI[2qHl>Mt$HDP8k1ѐ,s@7s `s@٘ȑ?aL'  a(iȡwE!_V݄`m^x*!890%bc;ELm` χ,A6{=þ{to[,{\+o,_-k<*{J8ɩ߆r5ԽLdjsNwk=W^&>9lnRBk}%BJ>" j<QQkCMJD";5CPRVL ڵ܂ ~uP8r7(cL4T` P΢u|tB,RgO (Cb>?Q`\'BN|+d5CsiK7~ ѐcѿ $?q4 g]d@.fg~0*8'T>K3CΝ$Y(_At)vx0] m -_Biۄ Z Gx _RZ#+Hߛ/ "Asdo@YHe8[>6_ hdZEcU{_DT& K+5п\TkRxABd;BeN"@AE"NGP с  K@9B\$E{R=ObJ>r"h "#hpPyw2Wu½(p^_²̶C7%mzN]/pKv@o?F*蓷$g E9U.Qw Hl2tC;C Ei╊@c=,#b{p;UnNl鄢3))?2bCAM& GBms z(Jh8ɳ^2Q |Fq 22CK~hBVMf 'v}SX r8<_<%%Cl) , 9`H3 L_6ZMbᄊ0VKp{w\p018G#8@lY|W\9Dv^æ1x)j!|2%\¥Д}:6ݓEЙ²rJg=X4#I!vZ=:_ $Γm'JcRA*ܢ0[~nXj-jyR :h5"c?)`P~6ZlzspCB^;TTiWmgӲTi- *MuPAӰܿ[,U@ )h> O b*nmȊ,g_̉S8(WHV,aKK=xr^|[~J;۲yKwjeۺGA|'{:Ɣ =FXnaҮ+ YSB(,`_Tl[\:|us/O*/H18vy0r [_"Űc|j3)+XL(k!P/{2^+@ y3x!x!PoĹ[A/lI~B0}0<la~\IřI.|$~C 匴PpHy52"%1t@1xOZ[^F RqF> [-] |zQ]R1`U>T *w@  e.$ .gHrcnIES厳IЊ(P DMHX'Vy i v# 4,.gHCA)@#cp!G*^VƤ߀=R|}~)]Xc5E A//ot`LDN"tW;߲ 6t_@)Y1Y\?*z85 }H\ 2!)2}w^n9)9Ԏ m #m\;̔#X&cRӘ=kGxBC`}$tYFK=)e ]Jhf:3\S. Orě^M軛DJ^e];WR6%ƃp;j/'TI>2FǂfoFWR Ky{FR܀ISXUz4 |. RR\\ڤN 17G$#knbm#ȿ)FJ~1Cb߁3!h HdfP`c䚀'TZ5(|6a *E|4k X|R<ج#;( lJDIO+k5$lrDF3Ry])ّit PtKDҮ093u8)R~w'ZiQHqP\V[I;s#{cf{pT*B9o +dD9Ev4RN/1d`Us.l@!3j\fuFSKN6[@9 pAA0#h L9MvqG9b&M)t, B49] jlrB4`2G@IԅQ.BJQ7ȚC8"JlM9QʿnS (&ٶ-:XM"# 7&|tSJl뉂#Kh@A54fĨqIA ()P"A)WLau(S>La݁: ){P( gLf R4-d5AZPUʄRFҰ7}t(F|EV@Q708@dBi{ E&(FpnJ)NY0:ǿu[,P=JkSWC {-e#(qHYͤv ᚢZ@j$.D5>eVExx`UA)*`c"PtR*kD1@k*)R޴V~i?ȧJ@Yh};,T)[QVqF YWAgu(nj2r|&!RtbQeqy(.PƔ+|(Ch-zWQ(&JHi]lX~ ,B{ zQnS\/g%+|_OF0zhс#B*=yA."ʛ-?@E{ pӁЅMtk/'%R+aITj;0+ 3W+{0i:1rHGZ-A7b7 JGfY(y0I9x=u 99Dt&>y<+M$9;BgdAKyLP]VZ[%̰y\"ٔN֏1t)mD҆H; s4Ot+8IGt* Uձ^Ztat,{8sk2ѽ ?-D7^y{R AhԦ{q *\`zK~4wmc~xE[ݩ+]ғ 3 ܵ˭=NwAؙћdwҟ=,QPk߁&='4?oFǐ >ᘞ+YW+0ѷ!̏)P5G$g*>_?}`߫^|u;FT:<6:-;{8 x0Ӳ$4'@BHhsm/dXBf{chf3t7(I7x=DHƝn=8gn5檌t@@E@U;lCZ@Ed?A%XPj4}ݦEαUz1*KTȃ3e|t齡JSڒ`9; ]*}T+G4fu5DV @f?xj`"}UT5PFe!;r5 fW}hT|َAvZy*K5e9}iJeg_H1a|3z&ၔzAZ9#Э/E(uwNX/uB$P\DSbccHp1~ \e" Uyl:e bک؛Z!AP@&RpJ\J-rtjs4%P4nn3tQW׼#gV.uIf` % St!;M@OD`-(2DI2FEIl%Ah/F5fJ A{8")H%dY3Hv[PIϥk ؆MHP#i[u = ɓ$D\?o`G()! O> hEZ0Y8b< QeK)z=fomĨȄMHޝ%$ ׀ߴh3euLx+hَK5OF{%x9o=gqMj(jZD&HY'Zo(x:7`iy}pRM()(C;t)>|T[)WTH8@zk yq@d;dTͫn^oJBdb2+ѩd *5HL84!esCK82&>dhR%Ƌ$ g?~0ZG[1CIx=q, {~J+PN"Phr-_.2Bq1|(1EBE) Ծe,@,"t~ :6%Fu/`6ug-ApiEpH y"Di7u@o;ĸ@}G~% qUmW% ;G+O3xj(Q#(D˫k(m2^t+:>M`(Und¡] rTO^A\׊RLJ$^gj?-z( w  z:^bJA\ػRPi_ ND2 !& U:& +ds9H*A/b<7H}2gvd2wj` eo 0AZ}`i yD5| 6V&3૆mK Fu |Pp_qse1@ -/|?H9/!HRO XphPG "V-&Eo?L1?mŚ2*cU%lPpkc<y];~m"P@uZ | ?q;&WK@5 dvPnϴm'?m1;-+v7A  ̌Ae疜ؖC]-}+ K4fiW ?]lWf|ilecK67on̷TBiSB4=%5T9;@24%1Q+K2#>0%F<.:,4|(I0!7)1z/OC,M9*"DC B'H#E-4:6~6'2?\;8.NG9=[3E@"Z:VB-x3L.U)WC=:Q/j%y>6j ?\(@87yHKVBg?ٹ 4[x8,ɷ%!tRNS](  6 Aoa-UNɰ?'%ݨܴx^xepK@@宜Z9*ΟuW4-!ϛl5ߚhdXN%ӺsL@J#¥{m^I1Ķdﺣ{nĹ{w7.njS^6ٻs!T~#CIDATx읿k"Aǧ2^ o{ (^NF#5wmkG٬U.Kdbnwy8&SJ7(86asu菀Q,v b,BxO ~%b\bxvת\`eJ`Z tq:] #mF L!&DqMJ겂48[6Z#PiuݿRvh$@Tka61WQ T|(֮b!L1Ɍij B5IہL;`ҿu4.{]5>7h;yh<&ByH{C\wU18ow)#,/z욻 H?HJY&`kettuznQo)vJڻ] wܩUw.F3`l~KD͒|c$V7-(*kikάо6O*讚(8]ǔ:^\?P>)?p8i"fD3>@?2jQY+pǷ4g!HS=Wbn!LÛ3Ђ{s1tڟ<6cNJW3u]OlMS B 0S0p"~(T"HςY5 R3!JN3[qO84do|ɩR !ϳ>fm=ܿ@Y;O҆t <Kf1@ 6(P¥ y- =F5ͱ[ Ni 4!P5;P \?Gm;*QqXG.ߺXJE(ugX%QbSOz` S/4&9B]#Ok ~z ˙ĆL½8>^ʲ! y5wk"zYJut΍[#1ﺂ^g0hφi5""i-V}0qnGebVr'ɷzMAa[ {*wBWI=vMr9ZF%w2A#i|IU J+ޙl-8%y$T~%DrY/^T$g͸)mBxc+6Ŧ2$tB:@귂Q?GfȚ;C3y"xqA4 (xAEpB"x(( "xh/=B4 H.a ճ3::fQk^uߟ}ztWw6XyD:qD'`./X c"'゛hb! L~ed t;[TzeNW2v Yd o4LV)vjyB}-F,,@MyYX)޼ 3YpNΜE_!ucڱ+Ms.xR`Bo&c:U6t1=H4|K]+XmXʀB&Eu56*La4Ϧ^-ͤ,Ueq`.Ði+xƎO7Tk¥7jTHs5$JUR(u Fdx\U]lשDxvJ[$9Wƞx;y;x)SE?T,ͻA0L\ U&%de±@B|jޭ!ÌPEA b29u֋MF(cA݂; uj>9{"i\Ի!AW۱P)mK Җs.ŻEJܕwձ9T 8܊& &q2Z#x*j鍦qn t}8i\DpJM8MP St+K{7;'w3B-nVJmݻAܚr܃.޻2B-|." \s~+Y@̴̉ݻyo=e?,^ V| tGx]w`bKNt !neOݠp*3nŔ^N]wK^`z8uV[ˣ0J8nЊ]Ȯa:*Zkd0"=hAAIA@]sn@m@c E\ъ7ty$ڻ%` ǰ nGKpP3lB);M$7t0ם-ruTEzNMw)js c}U=5RH8m@(Hpڪb?pڪnȯ!+Jأ)),8voL~т(.ջݱ/P5 9yPVhX͉Bn>F aUhˠ\莅W[ uF o dH\~0$.G88Wr rS4ZlDEG b~ht?ΐ1cPA N:3lc0LዬNf9w6L}_O;T%D[Syw^>Sj=V5Ru4y Dч1wݳҝ^DZ7Mcs+(eRDyy4c蹋uIfL}<fL=wUyql0Sg"('zn|_3Qm[e=iJF}@i^AXCE\H9F?^3aD2wMIw!l)zn'n&w#E_Λ&yPb#۶r"cTNoq&H/읱jAǠGܺp4!B" $U n8v,*]3Ug^wð|qZH"G: rқ%"үTPpJS\l%k|*=H)s :.'VK/qdɈcKH&]&QIwlt L:rdʾtdžh&ݱa9[EvnwF;격\I@+]o;Mΐ+ٌiXdžlݱ WJ_[6Fd+ }cV}c#?DQn&K9n*N)=rHH.xoa@\ K`-+H)g6١;O2\Ty"ҟnBס\.|]Fi7,$0Iڌh VL-BžҋJoHIPz7ƞmx#giG# `$v(&(}*^4K*SWX}"qFrG#\j"5GQ'])#:ۭ_5~2f^[od֏ZDr py4\mM?Qگz鞌Y7"50XMonG-N@8m*~4NSaYg #5W N u &TXSÉI0t?RoM6gA55\vv N5L { JԚUȎɶh|2]aRe55Dm1h?]8Jtx90t?5]$'ijSeMMghlqJr&l58쯍鰍,S.vn`ɑJdgs J~GN@>;8Nx:'̬E(ζ%RINHiTlKv?Q[: ![)Gjx>Мerϥ:^ScUH:;j8\> mɚB"‘RAqȨ )Q ݵ8BHا\ ~,9T鎻0ǢL= :'S- !55Ae] 5wI҃}_|q+=A?v|kf҄TYU7Go õ>٣) E[I_)8*ʻz7%HQ(ռPR\ع=S(h~ڻBLx zg HA[':15eBn%_Ӣ9? !KIr˥ liC+уsvћs_aC PKK_/4|ۨ *vnp`<][|̨rMb96~ߨl!wy*Rm?!ըaXv˵"ה o) Cgf1$z )^+:1Yl@-E}h"w?}Q(M)3v KSVLcF&xqz4a+5O͛q [/k)8q? zC:icCgLcrCޓnO篌߄$ 1PɴaIIvcE,ӚɪRrM+y;?z3l0,+|<$hj,?q-z'7i#`աn)GhtA<-O]b/IӀ%.K98`ˬPo-9}dH,ˈ>;c/%ժ#(܅xlY-n0wjLܢYw\t|`} % tA-ic`P2*XNM6OUEQTس^ʅ`P3t^!Ɋ.Ep~UlYΥՉ":ZFƂ}|4T(.n_ Z@3$cKX,UbMѥ*T0ളSAm$UXݫczs|q\ZdU8C3C7Ԋl;Ksck 'uY[+}=y|(5nAq%QҝVׂV?ֱa9|p3ݜ0pw-ê!IZTTU{vF#9TwcԺF0[片}7|FČ {Ior%6}C9/t7^>!ݾ peo],}A,>sDCX^2*zfg.#qm,/QGR5vk̀[3x[Ȳmr hÀsx H%][e.SH1orNySb?n1hK\5XkoB[]!D<|b v*z4`vQ,:lMl s9pޖIUеBr-ic~C!WPkgBwj~A1ӗhJ]. IG1r'=),.$%s͙}\*.={ԏ,kb>jd!g ێAH, ͞|T)F.武3|d#L&Jwk~/{09L15sj{'(9)ͥ)߲+fF}xJ$lZ !}5wPo*ű9b0ݲ w0BGtRNS@fIDATx=86$ ̿-pk3TW:ұm0 CQ#!|RG x5,lB̑A +D1V5ȗS$ ')F‰Ј`WY>Fq*r" P4cD !G=>q;r |CYz lJ' l!X=aAPjԗ A@dK@XT:N"jԏ AɎ Fun#&p~P><'‚>/z F LzԾo *Ĉi6 P ⻗Ai⣡) >*%쯝w-#P'S }_m=z AbG5ر3,t9)b?q Aa{Gޡ f(pCm4Հkq4v[E&@S_C3qذp@VcqE tV0kyX|H(L'/mvMw !?0{ie(xm9KB;3`51%CN-k@|| ^;|(B YNN.E ,ΫgR{#P#o Nc5e 0.|ɯN/FӟFu j)|6 2>طraԄM~OWp [6SbmPk>: `3o,]lb!>e05eK@]SU ۊuؚ>"keTLކ:6/O& zE`_3%L hMXjB[# *٪x"DcYcR1uN}k̈́f:G`e7ˌ caݱxL`{0(>Зy"ph,($IKw/ FTf5"d'k.%&5\MػV{!NXgu±P%T&(x:2 M+\ټ. 9[BG6XXkf9ΌvlNmlMt@ O IDATx`7( mR"jB[ZovqI5n%Z9g@99ofh? \;VJJ=i[gб);L@k]\ɢ'՚2ތXRDĊWGn\EeO³y%ad{zQ.ډx+wѡc Ga0 3:tAL0H;̠'60oo]v>#c`}*oEG6Fe9Foen"bVT(ѽUt`UlmŢ;r<ږĒwY4w msh ۧ&@УADDDDDDDDD!'n]BSvtbsW_U?P$;"]=0.=rtPzRb8wmI{ UUr] P.F?Tym<Vbʿu}e6Fu+EYS~m/B낸Eӭ^.1ѫ;($Wt.KG<@!0zn1b_CDDDDDDDDD襨8 5Dk}8dS '4Btr@%@䀉2P2\8FD#D# 3S.!BY$Z&fRJT20rM= 4@W 7ǪI`/FW>̡7>w'{q0UޥKFF !- J^B(v00}FۊEKѽ;D`УDeFPF̣7ֱW!pi|LaiF64&و)lfϡ}oi|cκ0 "4V%ZE(ZS:]Ko<K-*HptX;NrRģ'4#P>S\zIf2!U'SɈG u@C@DDDDDDDDDE<3b33%"pR)"MbBbL<db.583u5؍K OQ/Bۚ\t.&:d^ """""""""V81!Q'o:'@|bVGAc:1W(~7ЮUiZ*MV;|im}YJ`赏rJO%]}?'Js~F'ucj=#'}{ FjEo;+כ:s`t_{:>GKFRm=P;QAäS]:؝(zM5u Nc3ή\L$3)hXhHgJbG]}4A5KH]Z4|MW ,UdtY[g_B8w=}vsCoxaoUIc= f*-Y:*ҳp4 8!>x)e@DDDDDDDDD4&Miߐ ǖ5lb|`҄7)Nrw W'`-(;Ԝ|v4[jvg̈́C|=iƛ(|P]`ѯlv}_M0O{jo辨eKel;{@'몵 Fgo$Dt\FeZ֓DOYI0ˮ+uePtd/}]IAWRؼ&}*oG :%$NKK䢷O[@C$ gY@TUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU=8o=g1EpIENDB`pydantic-pydantic-ba0aa01/docs/logos/intel_logo.png000066400000000000000000000150441517143232300225260ustar00rootroot00000000000000PNG  IHDR7TgAMA a KiCCPsRGB IEC61966-2.1HSgTS=BKKoR RBTi@숨"q"Ay((6T}7o9g}>F`DdJ<6.'w T @- m@n8P $ B2r22 t%[j;eOv$(S*@@&X`(ʑs`̔`)d` SGE3(xW\!Sd咔Tn!\]x87CP؄ ee3FvD9;:;8:|?E񋖴e /B_TBfgk+ m_ _׃  2r<[&q?.wL'bPGKĹi ˒$ IHk`~B[P. %w߂1w0hْ 4P6h>؀#;x̆P8XBHLC.,UP%BZF8-p<^0 o`A2DX6b"ֈ#Ef!~H0!H "ERd5R#U^9E.!==F~C>@٨jڡ\ Bh G h%ZBѳڋ>G03l0.Bx,c˱b6b#{";!0 $,",'̈́ Ba$nD>1B%+uc[!\H8Ri D:C!d6ٚA% ry;4:yBP)xR@\ RƩjTS5*.Qkmԫ8MfNEhhFyC+:nDw%JaEz=Ca1J~=+&ib3 z9c; _EBZY U| գWUGԨjfj<5rjjwY/i544D4i01VjYYlۜgK߱٣34545Ojr0qpns>Lћ=Ejkh4km8ndn4ר1͘klŸx$dI}S)4ti[3sf-fCZ||L OE57-I\t˝׬P+'Tj֨zu44ii50lmrlll9-/L6u}wϰ0ۡ7G+GcWLor ]3:B:;}rvq;7:$pesø܋DW'\߻9)܎n~}hLڙFY4xx>2yy z[zy~c#9[;vi{o?$L 10(pS_ȯvlvG#(2*IU<- 999-(yr`GryPGTԊ OR%y;mzh􉌘LJfbq4]ڑ#z-ںhT$Fg* Ki\˙S.7:hz4k]BX"\Ҿp骥}˼],OZ޾xEኁ+J_S}Ay1 W XPR$/}uuu맯߾sr}IERaofbC2]Ioot\<s--.zbFmmmMo*VOuw)y}׮zKv#swo}}9Fv~N~:],k@ Ç]FƽMpXy>t(h?8:V܌4/nmImmk9>x{{۱mDI͓eh OM?=vFvflŞ}> uzwq%K/s/\qu'u;w7_uzZ[̞S={M+=; wz˸~+?R{TXqϖ?7:zA?q)iŠ`Љak=x.{>>R/;^XW_FcG^_NVJ3^=~fm;wsw~08姶ANdNLu cHRMz&u0`:pQ<PLTEGpLr]UtRNS@f pHYs  iTXtXML:com.adobe.xmp e IDATxz8a 8\ I{l\_u8* HI$Igȿ+)t:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F (OQ9@g2]NL2:сdt^I@F2:сdt @F2:сdt @F2:сnX߯@F2:сdt @F2:сdt4t{6gӐmH)ݾz&׿bVi`t5ܹS? =uo5&o}6Ң7:?qC:, |?cMj:[vw|:rL_w;},4M燏[za.;-ts٣D8DgNj{lq"}Z:v>X)!f9m@z;Gr1[FKw)Z wgzgͮ%^ѫx}p{WȱYw8[N4}W:Z]`;G1ݲT>ӏζP\xivEZ}C"я9kw }G# ũ~~9dvݏ~---wWҟS.-2mo|ψ'GGmGn+^w=Xe~7ea8˅9{HR[MkH)E92gki| ?21D|j5.b<8N''9w)y{[0N|Z vg mmh zc`5lZ0lɭgOx3=h/:&<-T <?N|=vl}nJgGq\4oA{z'nY9= )[Jc 6܆P#78W?澗Mڼ3yYuyOcSݧI:G s,/ԁAϙAAw ȳz?L2:g @FC)iu㭡w0=reVucFm7u cvZOK]4N;ar\fS_T7g7Ap0~զWꞽ+7FMf>/~ye~g4={5[bno2׏&|F9%~Vu]<\5a??:-<5Wwiw=9'3Oyzg05 zg~;.Kun?!1NZ!{} yX3.cF%.g5ꠛ)s]3}A{žN +OX>K)RJ)It\F__;ܓK<{ϕ3H{sP: 9}o{\9z5Rmvqσd)}|{ɖO&Je)UlӗճY?Wfv(,usε]-ԠzjkT.3WٵfN)W\@ ǚK?TzY|+Էӯ?[ g^}pQqD`='t-3Ksw-z^ 2<MW/μDoy,ik17ɖ7K09UR{*O1)7??`sܫ{%[tpndtߪdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2:сdt @F2$I$?;2@qyJIENDB`pydantic-pydantic-ba0aa01/docs/logos/intuit_logo.png000066400000000000000000000043671517143232300227350ustar00rootroot00000000000000PNG  IHDR/PLTE&i#l#m$k#l"l#l#l#l"l%i#j#l#l"k&k#m#l#l#l$l$l#l"l#l#l#l#n!j#l#l"l#m"k"m#l$l#lo#l"m"l!n"l#l"i#l"j"m"p"m"kf!j"k"n"la"k#l#l$lU\%gd!gbYH&x%s*U#n+#l#m"m"k$k%p&u)MtRNS[̄(rmfGȯD`.ٜA~wQ4ח!g:_LFۃωZIDATx`@TUUUUUUUUUUUUUUUUUUUUUUUUUUUUUص椁0 [,X*(CRTZ_~ϲM$ڍ\,={Y"""""""""""""""bnoU^kr48l(Z}-J}Mvc5nylC)+x sT_Sढh>Ӫ{.!jDB>bOIpo6D5; ,!U3U!(ɑx;1a.~z=Qd9z7=(ÑL^赕7я{X;GO>F4ZuF/I0zxFz^FaEhdŊ`"EYd F/Nsvw ;E0]F/Hg|;cb#7Y"7E> 3gDo9KI FLM#;辟,hg~Ym6{d?/c@qꪁM=X9M}I7Fe$8P4uQ/~r.;+z. !x2z$|C kj5Dӛ*Vۄ๊.z"~s_VC3Bp/D?i;Iwb荒ӽ+Y㋆( Qq_ .~ݢoZF*ޫZͲmSI>]B4`t_! Xu $c6}$F//Kn/{3ϣ]KrrfvK#3ч)7SDF3zryJKѹF$ct?? 3ʾB>ǴmEt=Q?ػ۝4(mQ[@ѢEY(ľhIm047 Y|_Ndg1Х :D_OpmD#zD':щNtD_':щG/^!:ѧ@_zC@93\.tHH ^kY }Gvp| ;! zۢՅcgF*DWs +EځnUОs]OtuNMN=>~AtOѫzcu Dҗ؊1=E?4*Z ŢSjjh?,HD( 1ѽE/[ѺaLUQD}͈Z>BQv[ΦыޢҘyMt't;##m5g@t'ˁEWM_Sn8H\3ӎ=W}բ\$tu`Q [ @ "VyTLU2)W[jT[Z%k *;C[`ా)b[cȷf6)VVV$r`djf_Y얎ßc166xDΤ.|IENDB`pydantic-pydantic-ba0aa01/docs/logos/ipcc_logo.png000066400000000000000000000415051517143232300223320ustar00rootroot00000000000000PNG  IHDRK9wPLTESLSSOQPSRRSSSQSSRSSQSRRRRSRRSQRQRRSRRRRRRRRRPRRRT1zR1tRNS 8,J[2f=D`'#NjV|rPwlbB-IDATxr0$@D@hTbs;m錓:& B!B!B/8pS.5_t~b~y ,"aYUp'XaCbNm8), Tm|j4 k PgΙJpĵtZl*D^D @\eTf遠^ Ϝ6=RXGPH a 9N׀]sH/}7IoFS~ۺp#Bms6ŽRnXP#{Za%)^EKpn=[sl¾h`Wp)b`A}gDjcӗ ?sML!]{bu "qDhM ak3X?+v5#h@'rP=9e3hpRӷK84Lql:B!B!o=ݠKPTMCT=4϶> 󬮪jWUu%Tx;s]U׳tFy$c䘓LMKѫ>xvb,Db\,Ǵ5FN-ך{ofGԤ07ݟKJ4Q9W, ˒])<h0{K)Rw&\"7q U6|]xű* x;Nb,lYN?bU:'=VINǔ3m^,$gY7wBͩ\3Vf~[%ei}: 80rW/CTBGHjn / ƭso>V$5s.M?+l4dy awGHGu)yDY>D-ܹkMן^h9Hmu yQ@aGGhL~[=PkOCTwޭvvYyMTvg4Ry/3S}ΡH0BDC3\nmz'E3 IDJB|k@tg0#=_}7i::D&tq*r'vPp 7qNTݷ ]˅JgP#z{Ԙ4$#q&D+w-W 4o,@ M}qI`7D$RSi_+cv|8_z )#`+$^2܁bDo_ l\JiUI؛zP`+J&lVG8nQjUߴ5b?(Bq02,*dP5yC8ˤZ#Gilm&!pU,$=SC>B錾r"83kC{9NhnVSRq(" Ҿ<(`wmi!Yq n3k0 78f#hKYw;.'mK7Ľp`bkY_5*]t>ԁ6g}nk $B-  {[aK:Y1CHR[@*99'\8Z "PJon1RBN؜imJ{k*х-B6B9)saw#Z _ ݃P A:B.|AxI! }tKnҙAڿ_/!; !a/|IIƣKߦ3.|AC/iKڿKڿKwfKڿ#Kߦ3. CQ'ADT`}\[X]́TUz{saZ ^B-xXE{-[?e~rzJxZrueZ?I&9o"5PBo)Αplx]OP~@Bo˙nʅnsWO_3RB?k9s=\h%z -[Zr -['âEE[9vu)+GKXފI2h/:}cyv.l SI'H_}1 |O;^hϏWhST'[?x*yv.s U2N-ڟ !>K%h/! 8hOоI|TB=NNK]L*+ -V#Q^_B}[Z?IBC:[.t@Bko/\žʠ%iFI$&a= >MD^J+bQ uwoθP΅.FLBvvvb"pf-0R>dsM7f:J D{8=CB{]t9=c&a0W&A2FL >ÙbB*Ix :g"gxѣZ0u/ϭ޴i$SxOJǶjkLf4_m:&}+=^;P<MBM?Q_hfh#P=z}40t'5)aiZzIT._%ڣeZr@õk&#xի梅H; FZ>: Ty"60<ݡm$Dgvs8e9 c9퐲ف ut@>N;lv""ܟ˳jn|K8gJ>C3V,D81ŔZKᮥGP{$6klYhd2T.Yt־:|~DBMlNy5بо{ьe"彑W6.!>L%ax {]&= WSU)̻A8&̪ }&L`֣6jZ4mz #i-[ξPV >i5xoŐHDSBm^f~k3 xR& ?R-nϵOmR!|u001_݊:&!Y6u5"9 Ӏ3^+ĺl:ղDBrk~|)xjwWﭪDnL9 ?nnMC9Κ8ި.ijYHpޘy43x(aJ̢x,Z7DY()PQ" =F(z0]FȽiz;e_bjUU*UTTU} +]6Fg7w'wAXeDN &ٙK,TĔ r<+FE3R߉V!}FIgH$'gv"t8Fρā0Ɛ| #Sc37hcېgy.̛|}lOo/+-jC__"3O4zJ9C5a%V9FR}$h,yt6ۈ %`ׁd࿔&$9q9.!45"VV$ifsYzqok/Ra+=k+ݝt hݳ]>T %əڠٗ_o~fXW"9sk/Ykv5頋`j^`E.\ï8迵/A퀓4ϡu(VǶfSB Z(`: }٠49U EN5ԹVN{Ζݒf8aPjn;=ciByv %. lKS {a1G])' `ƂhϊB ia" )TTI(1Nﵑuʑ,U1 m˅}mo_}c ) [gH@SЈ0T6>(}aqydy;2r(] MѩUl\h rNKV_>h]f] )a-'DvWk6IOS~"X $t6YCxhj=_U Sp8hiF [I9Ή.tC$ ?}nPHb]RR`"i9gg@؝\O o;J׉&v/`*/2F|Fol1zH*fpbIIūEv0{>wlH;h{wl@DAL45P032y-|c@<'x=i .sB<)igxu|^rBsH礭!u9]!}Q0 F(`Q0H֡ە桠 ̖܄(2eo,]$qRuKfjT%,. i< |櫓NzuzZfV=c1'G#Coy\* ."<Ś:zjE]>/|&ZwoXQj =ͱ} &_>t%Ky*-tg[6#cm"bywݣ;=]f7Âo@ P $BlS#T7.Dt|:g#Gw94Dj7WY r-`p[(.*EBܑդRxp a92L^1k(\aAqpyC{8 |B.3*t́BNAvFk* P#DxFUR7 k>`IdRV,#κF6!c. &-BJ (ʬjs3k6lڰn}!tlwTXvbZ6¬CXZ7KZ!s؝,RpM٤8 3o`6;¶Fx:5tBnB OY>aޗu37 a2+]@ Bg{% ag6vMcB;k}r f6t! p{-A7N:l?` ޙh)Ca,aMdW@~:UEMMM,>{MB@ㄐ{o|oݱaSy3򶋕_tVR=}ޚfJ$Q0E(l[7*v]c0ȍLh!em0h^dƵ4/C(ht_DM  !<+-\wEl Bjd6FL|=>Gx]yudY,#ξZCI,9;7TN龌P + { <5~&BwFh0y#=!ozs8xs9B!)Fs\€XPS~3ޣ 'w',:} Gn^FJyB-NZNc.1{UyG)kFK5:-6elN>s7X&6@53%I^XY]LY/&6UVj~9=7`m}s@u^? !6G~Jp';P$9i;"Qr>{%Kc%O"oNۏP:4lG&o>l'糙'N7O%óSǛN[MYZjժUVZjK\) IO`aP .~ufG~i1&ꛒCt0&H9=@/#[+F*狡O/a}dBžJH)L{wqn#\2S 7<هHzw9l.&3_fv֗1pԷESpÇiTߝ)6q{Qܙ3tB18umbSt[01IYnU-ΑJ~yI%B܉J?5{2(ji#>U lr`{Ͱ>Z!1*͏܆ {ľ0Jܫs#G6"4ajg!GqF0Ɍ0 w Ǩg-"T8Bg'AQdganbC݀ ++F>0#%PiA~ #WDPy .Jm_·<k6XD(2B<&C*OKa+bC2_B>ƊKP:Aœ f+`E1BW`!@6Bf1WJ aF*FH7aOsO_HT:إ,G ]^bi^cdQn|PIM (,r ]`nZ<'L۰oͮF\'a@`4|3(0쵅(@]@x9 JWBp\e#RAh/T3UZBa-D!(X.HY=/B}dS{kDar||l@xvqPBR!8k>E?xjؒ at׻U!^7`{o*/y=$qs5R3G5?, Xzg!(3_Ml]#O>2c'}' =!i$BqkJΏ$Nlr ^Erxҽ^f=$/NgH5g]H;)Ari#RA(U> C8 hP&hfGyycP LS|z, !e'j'jŵ Op?(Z-|lx'[tcO$ez%W|˪UVZjժUVZjժUVϫ0Wm"o7΃9ZXG*$h.d4ɤ~͉3B`J it,45峦*>rؒ'T8=2:ׄ/am >F!u[Lm S^78NKu8vxk9 d͖2ِ3C1?'=9z520aY+0҃F)aXRв?M$R(3C+c (Ҳs[dzy?yP$)0.+k+H N=# A=ÚCҮ= qеf]RhvQ΁`j˶$jj IG0l#`PRle_guBI$Wl786͈:ղ V+E!un (XvSd. 5Ij E M#qUl43r Qz:wLCB}[Q/:ձ7 {pTJ$[eZrl\$_Sh@ti&H2fo|h3Z9 #W׃@7(m7I_GB=nAKU$|RzƱ5o\\S/+T>2lbmp72MvH6-7?CƩUIӣLoR(xHUegHonkM ڏKlBͱn:̝^%.)rI3 #HE4)>pma&\}cZG` ` F7!b̑.}ZwVT0 9Q·r(^4J X/VAҗXM]3Z?(4wjGߴ?n/z:ҲŵFiA" `:K+A<sD: /&5JO !YK ߯wf0)3V/'›$1;O7~5 et!);eQ8GɄzSzƉQ#V80"W_X>̖O;u,vvMV)G8d+älaEτ#tV:Kf\[ad&Sgf@'\jaߦטWm(KJ.$ wY`|Lh? 0,fw*h ^nfX@^3*K\s'B0&zD#@p,q;Rul}nbnGe htnp;F+NJ?/%3_wPq#p4ܮ5;ӏUZ%Ft$1חI }ީ^IZ!6AEq6%>r9w‚QGEXU}"Yʝߝ*ec?nင"YacH #@~Z+^FW.x2 3Vϊ8ZpzI\Rpݬ4|gK=\'ś$e9¤'BuFؿ$W1ڵݶq)I Kv`f3I,IkUz/L,_}M?ƴs`ObV(: pvUy:ˬ,W)$-P$J63n$R2kI}jfv7Pf;U,d(ȧ5~Z7IMGN?As쵅~wuݍ#H ̵N^Z1r}>yFn+Q*XyDf"g7O8sZAH5 R}o*s&T~3BiCM+0]St A׷3i6$|D53$2wLNZ9,[)۽q}j|A,ߗ0HΘn7QKPmUl4ɑI =8ԍ~2;Ҝ=#ҷgN;\$3_0:x&}.}s:Ry3<EJzpg^_ J3VH"3nvcD,'_?Az1-rEw4a(>ՙVb#gmYi:n;)?#5#i{ (U9U~7aBBPQD;6boc,6bsĐʼniU˓QjyT5\ZksYΝz!A S(kdWp@<)~N$̎!  JZ.'.+M][DAaPjE)p ? XLqh*pFK!vˊI1rj2o#ʨ%Q>e "~&l7ߐ(S6lҗ>: Y*re5on:?sμ,xtcSv0ǫuW"?QTʝQ^wIu5:j9Ɓ\4^.I;֜*3"uMP|&4 UIo,nk rMLo|WG}u, ;)$} u!sR򽬸ߋ4EDgzTJݻ.Fu§Tӫ7 )K ui d5mEe׊3G÷5gMpD`uPt `=֎ DOxBb4zOsakxڀ2`|J581liYCo =f&Xc{LzR3S9oˈlJwu_DohgYTS2uU[|5.Inxw[LNj|s[RC?3qS #cKH!Fӕ"kE}cWJ-C| 3l"+z贬]N L!hlȝ? :gƏm (i-]E^[!-,սw}-ƽ78ު/a^,RCMg ~a!m/.lrE*lo ͝!HKU%}VVib*yd4dUlpVB;4q, Ke-#[W/kVL!}da|Q{ L䮐u2`B#G[(vɥՙ㬹@[Z'PAzPjU7#RÄpF15AG)pSh¤urMhUnOz} /"B!0 V(EP ߋKrxW!Ro枷Awh >ܔ/X(MrZna·*oàޚB$wp`}!-M(&?(;Υշn skei! SrqS"2sG})=Ɇ}; [ce5oN3?9XQ5]A@&=,~? !uv g>;8̰i:e^Q97_U BP(>$G !oOIENDB`pydantic-pydantic-ba0aa01/docs/logos/jpmorgan_logo.png000066400000000000000000000175671517143232300232440ustar00rootroot00000000000000PNG  IHDR/PLTE$:tRNSjqv6 ۝{-&_UdO=GA熌ZK1 :#nا^k;IDATx`v$'(w, $M̰ 7P ~=>zzn?vjwۍi4 -I,K^V6ʃyr6{w*CgVwav ?p:߸sݸR%.Ϸ(]=ƂA`c<6^3/0zDž[N:7B¹1Rhq! bD 0liah`?p<~="uD+~'vh` RLn :~b[L.ױ?cDIxq015 'I8 Jd=<@?iOx"?<U#-^ՖH%g 1yVU&=CJpԮ;0on>|o-˜7csV^|U 1 FBcl1ax\~܊p43Anx@`)?ؔ%x@I,OERC,/G}l9腥MyTQ)Ց뺽}[ݨɮ&h!8k h" _"E] /q1AF'Xa63SAě\*&"{31OV3#1mO{P\ge(/lx4cMJ^d %=WIN2S `2ITr\5}|Y+H3aie2w /OղtOU 7$"L:M@ NMKK' <.A-}^~7ov*-3#_`#e5|%$E!~mS-5ToUx-'}jJthkG,-7(&ISHZDד+ᆐ{-8g@ѐ$TB.7c ._~}<3IIO)[e>r%+Jb-N=Q]m98O@&A\`.;HW<1}k[U#*7ЫLձ T[H=KBؖK2&Js{3 c<҉5b#S(Hv qEbHSNԲt>cc HX>ݎR:UUk*鐗O1#NR[iFA=)\zf|ASԐ:SzSV#=/+aRFION_GtSI7nJw qrZ:-s J=\9_ג 5zu2`EK:u ݄#W:5hHD+TJ3 [ӒbD,zM@Zҩʙ7ӈԦ>3e-s_nQȥS.Lt:3s ǔۘ(GB:u7~MhJMĥR"XS%R Pwdk[4[c<^Sft :+l!*N@#t*#O`}U.4֡_^^:rkXWKg~7KL~f%֓Ny.}hf8-RjRT2?]D~$+B<jȦ-RK&[ n$Xq>M\]}_O:HI)^KdR}a+qrz lnPIrෙ1شóMc;K? jVc~P=Jz/\Fļsqv7\AuSV5Ȯҷ4uS}쟐>3DRuqsx먥8 )\}鰧~xt"ī$-Hv"g$Vj"I&ciK"|Qٻ8y-=US*G[ג0xї>wN돔N49:)kKb!Q6i552 JkJniqibQ]7Z:]R;O xT} 0T*]o1+/Wqq/*=M܏N^n*kFSzS;*kMl%Gg+K%y4ӖWN?^ )f$tU>ޝ&YϾ/WK_­0w~u`b'[MNCoŎ&5ρ6m6?RZ%[;Jw .6 A0Zz,H1)J ,oTaNtGA͊#8@{J`dvAOOFz\FL Xl7ACr@&kʺnũ}:+Iz!L g2^^2HU>$Î4 0nN[ s,'QE$H0y (uld\Is&i f7,u({{bؖ<^[/7I!b~lU1yaq%F ihDf5a,1琤,m~fŦ3, Ƽ(q ۥsly+왯 {sS:¾LXYtm6AHvT1w.{,ϼ0zFwm9Q||r1U .yjFR#}ʰ92n^QV鬧Hӛx!%J#$49($}ܑO\L|H)מˁpɁ $u/( }GrogЍAIA{ٝEk;fY=pq6لYxE_$] sq95#J&0̋ax, 8aq᥏ܱxqja;_ɕO,ӓ*]*<ޥa:m1+8pfzB!OU~!OY08ό+pV`ľOà*Uh߳U?bmı֓.0c7Sw}hzC}߳rKY=gT47~T(c_!`UT>,O+AxޥJcD'|CPԌY8 LiS*bv:XU@ѺZ[̍[>ؽY `$;ٰaq*`  7̲关}`>Q8f*e692htX+xއ(O/,ʫ[c#mEýhKO!N:(c`pՇA=I !a#l!h.~c y= n̬#-GbSvG\ IM+('>57C-0v貇O8>VACz?ӝE7Ĕ!cczE=;­?ܺ&TNwQ~S1Uv2M3v+eÔvt?q~0["fC/_”X[)]ډ=y=KWfQLeEw3;#uFZ];v0v2LGe/Qœn S.<^Z6 Kχ\gU?(ϳ;[_FEƃ(q.~ϳ:VggF¨Xs) BH8Anwx|z{]cy+KkQW`9@mK7#O[YsnTvz54Ì  TlIАGymҖp l%`jp)Gʔ╼`l$`Pt|G`$Ut@2fFpbaN-wƌ@1rU9?c_RPNWy7/%růR*aPDZ@V:vQ׸q}FeYV>iጭp3(CL=0q쌒EwE{3eEaKnX+[9⃚S>E䩆?BE*S 'h|?rhد\|y3+0M5üۉք*3Zp"jԊ3F`V͘DȵJ?^U4ƕtS(4*d*Y>iI4C{-4Ȣ27)OAH N k窽TM0̑a +BXt>4bDLp0pp:ѳ5wf[}dNG6i7^:lTBpFܼEZGz":8-) >1&!O@  Peĕ;$%t>nǬ֞Zr,E/Ors^dxqxh7$ĈľբOKq^jܛޗc&m?׌ -~2Dzzb0NqI:>13pK?c81'[ {\h[ݽ+A0D.Cj yI| L|k:c3 2JW]wyު_q"gNO.:8DVYItscJEψcGD$zNSib!'>{ӊ9eYBq$/7tm5>梇FIa)Z} p;Y $:)V‚pb74.e<][t\kl-DEoɎwN;yb4BG{[zu+G|\ӣVGHC랿~ T"m}Ğ0]8{V$\>D]J`xmjٱ)>Xge/cusMn)Ӧ/W>UcjB7li:'`_awop/VIcAdfTXv87B`9Aúx!fPWj#KnI3Y?J6KRQh)og"o_W Nn?ed#hbFy>K5;~/TW|Y .ȘOѿŌ 6LfVzthϥ$s"inȭoRo_uHd 9SX=2% hQ\ЃS7$=x3d挪1]DO{k߶x\]Y;?wG!gR >]Nǎ ѯv>Ȝg*At+/N I*Ӏ6v**H lHdU**nڈtv,f4~wH‴tQJĝ̋k s4&9|13#""hlPf <1J՝'.iuQ{W=Q{tQBLKη= 7&Pý9E7Uc YPșR|o:%> _C[vſrfˣa& 3 ҤΰwupMDA.Žnj:+#ĶjXREѽ|\E4ኇVIغ=ѿ 姢~%}IDATxKhQЋ΅ %) ڠ)Ĉ)R4nJk hR]B(RhUDE.DEυdHMJSd&{΢i`aaaYvdh:LNO?8\InsFO߽7 ]IĹ?ŎC\x*]y>r9G˕8WD404$ =4ǁN!I7 C\IX{o28199y}JOlF+AfEop}$14vb*fV|)Ti"Tҁ֖ZLSW9#3CoP[D+B o{\蝖aP_C[ĉ' ' ߒ~[I}t 4V= ׎'Z|!SjFi?`IZ\&@%V+jhx[g>\FgK*\r0|f벣49sAQPεɪw3W/yP$j2bV0U=:gisb%Y l5[W0޻NbZ,/0(bsg jxȵjF_\S鯝A,^DP.[#H Rٽ2F$4K5FBAKf,Kի}$tKtU,4 of”:H%ɝ]Q0GJu4 (/ G|i^H3oB*㧠4/ e祘^;tvf:QRlRH㮦P|HV1GLہlkk@z y쳭@1PG2ٗ7 I L/mC~vo w@)2L@_GA-Si61b~b$qSs@ti- xX~XҸtS0Kx:lm4]$?> zM=t!zdRwiaj&Љ,[ϿFj?ʑSx/;a3n&uE-9 oej`7[--~?r8"`-jnżT*+gXTkZ"msr{6 cM.׶`wok3{\I zED-pr:lpbP}sx e QCu$ j;N=M:uހ*m4{Si3gYTV  UTJk]s=#`V#?j *\պf3kkV'Z>Q!",]*(94jhjCt]aR{vնѪLɿ+[ ! Y>*[aDz=ekݻl}{UE(z5ܿEκ4&cR>iQ,fNګLe tF9R)lYCt nΡP/gJ/]KjA俟wq">B E‰$)6JM)QOEOh`%\q&bXn)$ǽ_a33ySy1.UR\W7>"cU#5n+`k%ۺ$9sQ圃H. i&z\ HV^.!}Nu)1rw_9Mly{W/!{a}\]BJ5s΢8WAtG(|96jxŝOb` ~4[{ s:{@i3q+ݒu=&sj=qmh>\%7ƭ\^_Wvj31?y(Yoo V?eVnHi=9:ƾ6S/тK;r<`(ayi0mS>bvm h $1q0< ٮb`xky^gnw=jiUri0@cQ\ň/JĤvq3/F??ͩ+@aw$t+'ţy~r5eͳ6On nypLt2jc yЧQv =)z['{^: /im]tHF{]XӵQotBPa kV͡VK?ZJFYpEvʞQHbяHn%SS|n@a=󠫄sq$e knR m =N\B.@4/iEi jqMڢ4⃱UQS#҅~ɮ-˲,˲,˲o?/Jq?\]<֓({ك{c:1GD œzfyg~봠;g~=H$D"H$D"E1)+͙HHGL"Pz~F(6ţ(zDC(BQP=!E(zEC(BQH7JR?iF f|Pn.ҕifʱc8QnŒXB9}iΧpOMVE'yecYEZttbrJJ%~Mp+aIUsY4o w%& g%A Sʩf1R2|H:YD75e&MQ#x Ц_bpS"G1tk[S$w^ڈ>n+U&K I/F>l g|ԇe,Q_O?䊹4Ie:SDq Wك%:]|W!Azl:nezOkk&InbWH9+dr]svdYdw pqܲys2% Ի Yddw^^f%ϧ-&Ż"gjgkGUUFI55۹ m`Vd@GT^CJ/YlhGz~gա{Oǘ.H:?)⻋ё۰3I'АŻ2F4"yOΊ;c5?90?+zF_G)yJF/]1)H!VǛ-LKmѻKR25qt8!#4\3B&MZ9N9Oa7di݀+eA𾦻hVd Y[Og'h9(&iu6c8 73`7,WedZae_G?'Vju1NϙLm{v-~ďM]{1Ic&n1( 2,{+2uNK?\=M?aqjCޗ#2-=}\-?.}])rTR=.Ȓ=jйGFt1΋;!8yUr)2G#8яn@k@1l|V*2=.C>z/B!yE7=7s2+kztA98_}&:^mueO' n ]]+4ŋWH:}p~\9 CVs(N| Jt>ړv~IxۣHjnDk>L!لWdX?C2z4#QǺ9|ު-vu6Z$`ctidX~g헏4ѹ]Е1ϖc9'dGIRo(F>#:-?‡k2ͪk,륺򺸇)mpZ.ϫȲH==Dvzqt>,>֟jG[y)k .1C#zEPE&ˉ~OA'`/1me~BR B]f5{2z%ۏt!ÉḌ_ٻ{%0f  @ B;J*+0ҘX쌱;Q ?S\vsDG絛:d7T,`wQ&/觷}ܼZrB\Hr[B.^W3z~3эr*:uo;zDoG}lEitvOQRD'f-:ܢL+9~CؿCB?: sdߟГT\{#)|cԺ;Cƛcwz 7e>zuwy=) /zwfƢǙ0cO+ad zdnJyqX/9eTGoA9V-X8 Vt8ƵGxȐ3%ѵO&r${$[³ͧ\}!ג] &'gۘ"!#"aԾGrɢ*cL)4dAE—c{D:+k{ c5pmq>,gw6sBnvϣ9j%ѱ b r0H6uѲ;8NbT[cBNPQku6b$j;5lZb>(#<>BA^.jʦ1 /ugDBfDqitE҈A6 0#p-st0Q@4l%-RьPpJUBC%E-BAV>O1U5#iY'ڔ$P(ꑒ5^a\}Q;IW/Q+TZo볽Ȃat=AᒑI\I:M l&"U"lƢsY'Q7gktћ Q@Q~Y9jT*5z|7kBnb œL2$ZEh1Q3 q/D.*D6ͫ.Qh rYա*.Pnbl|2zP%])88ѲnH -ZJn`zO@Mo'0EB=0a(nsXXȻ5D9kԛ]E;9@B;3^XWz\7_] \:_E^tmwFԚ#qFrCt cF8(:H[,3+u^t0vNCUq-sK;Dt/Fo sz;Q1\{*ZMb_#_IF(>~H(HFJ)p U⁆a pr ;J+gcj'*,HsѯL6sNVLXv=@m5n2ݑ9ǵӪvEp ެr}:Mȩ^,uIg3P ^f\/MRGQݻ|3$]~FĞq.qUkI_d ^ߧ;֓ՙݬ@D(>T<3H>ϗ_spWy" Y%TH=MYgS8f`ѿ\0=>2޵cߜ%!| >׬ryqE'S(#Knv' Id=c4OOgAέыM~qod|nY>8GR!C(^[nǸ0D$ˢ#6ZzKNq\ Q|!b?_)|>Ov絉 riI$T B+^FzHz͟So)P<("< ,mjnoüy>Xx7OƸDx|xxXn1sX d .FE;Q]?&>f ,6+pvꑀ2>Z b$<G)+8y!3I*`/=$c$*`? ^q"c4#ƉbSd ~ ɯ)-/P 78%DaZO8!wOę38%cXVE(UMP0dz9d\폮&]=ZK[O-SUm@KǶ}%pA\([Å9 m4AmDDV4sMq M8eulKî^l4qgAKu¦PQ~$* Qb6Zxu %@Ul>"Ï%)m\K&qrspple;Nq#\ Z:̡3]zщ],](:/7jQy밾ЙOZ:P6pHЕTY^WhuH#BWB-]V5=V<|Tn$=d=a/Ŕ^Zưsm'_zC?թ]cCk,/Ocld+*PeQ>eܾc?yg|?D0(~!=ۛ|LkɪNQY)󍴵Ӂ?ve&rSIy7uv/ÆoB:K*X,M೓b軠 AeAܺC0"CXK@v0d("wE`o-%q'f {:"+- &A{UR ѧ8wt*a7qB3̛v?*Ѥݼ6D!ChJBH$$-B6 %%Mc6Դh @)RқX?(zye?uYbOҚN;Rxd{3= W!At^ȠGYo.1h%^[g n숞3^U4EIʼ5Bُ, @(ze0'S.!,l=SHgf/;DQFAb>C`a?M:?"r1#!ginܸ/ߝh#{xB3G=h 1?JB Ukx8莰&fSv,PV(n'fYg:1?uFG']^h!b^ha\L<<̻Oto/9H{x?P߀JﱅKi7& D7fO_r9دb|%7Ǔ?e4񊌬 8)`Wg~ K}#9oKZx^T}Ĭu&؉ `q4o;Kb=bqLj%k 5y_z=-k~օKߛ+Jkjs§H MZj/ A$"#}qELrNkl$kNWT-4>+s1seQ4P~!3[&y[&mI[&E.mUQ6l3fZ$& ̲,A9L,[%eWXف{RJo1qP3͓+Av%)<7$2u\>k pH4eoҸ3-WӘ3qq CΌ;pag/#EHbl gEi. FmV4fo-6<6*/+n[df*(׷\\ZZ*. lܘ$aK-pMfaOXbr/CYlmZOa9a1 qVO`I-OEmFg[nZ]-]'\.yl862awd: R(bHߨ=LW>& x/h1TF(*]&L̈́S.sD8rzj6n ƣYЭ\Ĝ'_+k9k%̠3H~}#Q ]^?H[> OX 6Vi +'t x''u$cL6kejJm3|~"͸/6V&[jGU&:A|*R͔exR 8T5JuPT\ZR]VOę թH_6n%FēfU[%'5Z}NGcy$踾@LčnչVlċ=H ^,RVEʆRI')#8CY;7(+KqnA[qnA[Sw.eDn,SVM濏nn̂\-)":t%V'g܈,+*ƤTa#$8m啎+H&y(:r,hH ]mxM_8YeN;y/@OIENDB`pydantic-pydantic-ba0aa01/docs/logos/microsoft_logo.png000066400000000000000000000120321517143232300234120ustar00rootroot00000000000000PNG  IHDR/PLTErrrssssssssssssrrrrrrssssssP"sssP"sssP"O"sssrrrsssrrrmmmooosssrrrssssssssstttrrrrrrrrrrrrssssssuuusssrrrssssssssssssrrrtttssstttrrrssssssrrrwwwssstttsssssstttssssssssssssrrrtttrrrssssssrrrssssssrrryyyvvvssssssssstttuuutttuuuqqquuussstttuuunnnrrrqqquuuqqqpppuuuwwwrrrqqqwwwuuuBBBwwwyyyuuuwwwsssPPPHHHqqqqqqxxxzzz999EEEzzzeeexxxrrruuurrrXXXaaacccfffAAAuuutttfffxxxjjjeeepppxxxmmmhhhLLLdddbbbCCClll{{{jjjP"O"iiinnn|||oooWWW}}}QQQ___JJJEEEXXXjjjQQQLLLlllP"___P"O"UUUO"xxx\\\fffKKKsssP"rrrtttuuupppwwwyyy|||{{{~~~nnnYtRNS($.%ðIw sC1XM5~*kPga\{"÷n9ٳ:rT>'dAޣwF&?U͆ZUM½Tǻxomji?22-zrnc^JJ?«jb\1dIDATx`@TUUUUUUUUUUUUUUUUUUUUUUUUUUUUUأc(  "beO^X\ ?[|3- @^˪uMU]lStktPN߶پktBz 遤Hz 遤Hz 遤Hz x~oaX^OBI!ׁS.ot;Ջ#Pqitm Ճi1zآF[UQ p %"ƮU5 *IAØїXPi\L9nRm3DgTQ׋ dj!<7htL/ȻFfFnzt`Il~Dgۨwu! 5Ӭ vRLtD#ND ʺџF?M&q䰕_k~fDGsa?Ii(\~1yF*^kn`aWЍNdH6CJ[6c/u~f0~2xѹܦ$SksA(~ʈY1͵ G]A :A7IsM!SDG#{)/DWG_n:Hד f0Vd!ᣏy?fH]nCNfIg ac~3jG֛[tHs^oGxoOwUqX4$Z7XDowiM#kvڞpP)'wȺur@h"(=:6Vd6+,47 B;c - V'`jo -: }8P2K8͸e(Z4]F!4F Ě,PDb@q}b'NWT$Iaeߣv?|hc|)\LNZ ̍sFB8OZNh]Њai針VZhq;ZHhY M,4XϵOS$cnktb4󾻓/Ng!:6~~&Ioͻ *--h܀ th)+ n Қ2JK3!3GKoZ>3z`U3Z|e@f3{ty?>~t2 MzbРG~HHӜoRw F0#Ё_+.h^k=zLzF[MG(ˏ|A]{WDضWCo⏴hyQu2lT30޷B#CCLvd#LmEn*-?hMs=>C(`v|bW|Ѱdd2$ڃi ѴW證K$aM~ эZ0:gc@];Ab+]Bؘ1DQP av6_ͥF0Ԅľ[5Fʿ ^-7z~Qa(@!)$Տ@,vNk7`|)FҺM Q^Kl Hmc(9HׯP{kP=ِ޿j;փ[}`5\AoG#> =H@2 %QK!?T ~OR-(L0eĚ<IWG~rk z @=G8}\!և:ڂQDLj2g ('πB:U!ii1*TB2DOD#(,@5Wܴ.v)"݋Feڑd\K9 y=ɾ31ʆW!v]8ncH6J󶡐;zqbF7 S^Qt"܃he/&ЎMDZI+P(":?jAM=߉py6y#![;׈7vtOF-fEf=mыѐr_i(Ie4$ شN谊v@ݠ^+T~Q r0ږxU%5Y rAkbG$j$;`7+E^NФ2dM =ޛSrHstOLs8o(Z=:BA_ rMcHF7WBX2>FWwx$k + I9Hy.?_d*35$?)L$:!R1mXUMa7@e;a_K9Ga>YG;_RB/pETd6ev $A܊ V4654&g%]; 7oYY#7<9+]YUέiXjnOwEFw]ntFw,7F_ }r/@nȍ 7F_-R~\s{޾\r\؃ FPUUUUUUUUUUUUUUUUUUUUUUUUUUUUU؃ FPUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU@@+T,AIENDB`pydantic-pydantic-ba0aa01/docs/logos/molssi_logo.png000066400000000000000000000125161517143232300227220ustar00rootroot00000000000000PNG  IHDR,,N~GhPLTE846856845##845845845#845845###845845845845945#845845845845845#845845845855845845845845845845845845845845845#845845845846845845845#845845845845845845845845845#845945#845845#845845845#945845845#####845#####845#################$##%*$*956845##945946N13$q,0%*(-&z]ltRNS<~\N͵ J :tћ1iOnAc]-%տYSE5}׺y`(9c"V+ܗqTỡ ŴyX>'I4BTK)IDATxMO1iWJPmQFWQBQjQS;_d7IC/Z^{c="""""""""""""""""""""""""""yv[B>! [B3B]>Zkka;|#7psMe[5Us%u9VAWC lVfܬBq׸Z:KfbO(vf_}"z'Y$g,_qa:}љܱ&ڢܡ hZhPTCKi_hFJRuЌ+B0Rj`ȳdzrgVEXNkVaݰ\WhnY~6PbU൴w!mGBhyʳᒉLxl^>2UC~s gX諯y,Cv h0\n9/Ct#CT6TCpuQ]GU30Uа+1ʹ*Y0K=@upy_Bkޛ_4I .H6{@KN4imԻA̩fC55m m:c>gF/0@1cojZu)^Q[; +M y(4׺SjN#S}:ՙ\7akucjf'}EDx`2!HB$ŸL$@I4Ľ'7躥"?bXy\@Mp(m qLr|W?IJy'ZK3e؍`%xbBx##݉qJ37[ X(_d[A3l/H>+}bčY{:>1BiV+Nn@%`:MRo.TŢK21 P-4rέKw;@ck^Olۜ^Xg)lIX% cE!bcd Ԭ$Ri4tdI Bn- hvX;$~TSbĚTͥϳ%^ !y +^ək]p})ִN frW$ G0ԋnt9k+X,( tp2vgb,Gk,8Z`:#ek3ذ P1 gH喢68Dp,r!$$ MŎoY-L!Hbaq< BTy[\܌$;Q-"|F"J&-RfZX$Iq z2m"vv%dz~f'Q2U(*0G˛Ul^^lH,LͰu`"WhmM-|_~go52907jMvOCA)% xm .g0/X"ϙʽs~"n%GT뛫 x>Cf(bٯ#Anv]'Q;7b} bu=uѲӠxHYr/k zSͯŕJbB%zkw7Y"\'ϰQ_6޿X+Pu,͈%"KYW5x$cEqVc9ux  (*bu5 XY;-;ҳnp3H b!(~:^ Lw; DD$͈MJ(`!+{zs5/_<$K&<#{ $gq7ロ5o%VB|HAg<;.ekTAЎV֝Ճ[(#n[sݾT471K:[<}8{ːgżM#Չמjh;ң"*\;:43#t:lDR i@3Ԝofxߟl&)+\QNO_t5g)6 OsoBWwAb,dC HҗQ?JEC2k)r 5`An)T\ iT>1 on«(T˷54K p-?_?))j18gJ?/*9ynNltn XcMլS 5@?"O⌥ͿZ!qQ,¨esk6m}vEXӲ} <Ȯ=6)55iFQ 3O#o*)SZgIwwmy^%{b׬Ŭh~Jo?39UcN("Xd5DÔ:HojRig I$#P,I,A>/Y@?eQy).Js5aI'孰XMfhG7Y XNlu$"NythzgɘUe!: xKYfJ ē~&u߹?dAMbQlUC)W,%mĺb Ù MbBh<^f4Jukk_lڶYڷ:bK"wùo!\Ei< ͳźl`+to f0W 2]E?/hKߨB/{ﹼ6Uʕ3nORksX9( o]|b2\ܰIc lD:#rG 4;}3K P]4n̑kI1ơɂ{n nZXw Z~BĞRm o&^GS=7 vDp@O8)AUeKemR *M1C'bѥTR#\ LhlR_SΉusUGc V[| Xk0TפxN:[Xw(~Hm5+DD*l%q:iu{bN#WWN)zcOy\ئDaPLYOұʣle#+TU{;ft -1UoSsneUK#ڟ>d2m}Z?c1k[r"v^'IENDB`pydantic-pydantic-ba0aa01/docs/logos/nasa_logo.png000066400000000000000000000517261517143232300223440ustar00rootroot00000000000000PNG  IHDR/PLTE 8 : < =; < : = > < < < 9 9 = = :8 = = < 7 ; 8 < = =< =!9 9=!= ;=!? <;9=!=#;!;;8 BP: D=@;O=6 ==! A >! ?=#* <;= $= =9 <===7=@$~'=-=/ >#Q5z=1={}&== 3 @= < @x=Gm/[|=Sw>e u<!;;b=6^LGC'U}0/( =W6 4Z-'npup?T%/!ba'_,Y(H%H̑b}+{X 90ۋw~6)v4tRNS 3U䏅rg_@!Jz)&לU8FerƈNPWIDATx:i0nc'q6L$+ԡ#aA]K8.E{d2@fUBj% +kz> BɈ'Џr'&׹u(FW0]\ kәIb 4۹ KC#z:17Bg4Z. MKSʐp\LZ/[]fu6~D[d{|{$Ox1:v_wͥ] yto-b]{U%ԒO7yِOeip>ٻ&8R" *}4tkMcSk@"X#p0!A/Tb&W5p`ԃETcϿ3S8STRSAډaWy)<Vw9mwoFL)*_p/DӎX( T:`gbHp^~rv }[#8(6 'N+*6˳UPVp>X?Hڪ?A3u~' ҁPT-/Gj=@1`[i+ !^-Azvo39( RVXDZʀ]O%C`=pI}{kU&1w4ۿʁIЂ 9%MVIܹ/r`(eiJ։TNݛ&;YJ]KD(8zBWxE{x05fd2} H>iw. U0G(6l/MQ(ׇug{*N;?uӪ?l.d8ԯc!!;jޙ_HmWB~iGv Aйo0QDE兙G79NddY¶^\Zb0dFߠ!ȉ XovDOv~d^`ty*D";sыv)T7F9@Fo׎ jg?s͆BB2h]z6QmPZC24!vm6-Y譈e wh$vQVs;1NT`Gϵ-n( xB0D,p=$SB@TmBSȋד4SŭEp G1saKW0LD+)ڮa_eANf1ƣ:H;YTH}<ݽ/*@ M=@911\8)4SigzmYQmRDU0\(*<[LbCd~QT փzꭱϊK@g[&nX#vTc:n`Yu@OWayAbb U#Y(?zn}\d|aL:kN&lAj#9$5E\r`m9KA`Ӫl!DP%*>CFsSfaJХ4=TTȍWэhOA !VXξ ՊvxTz#Qnd||a/,ny O&}n\'EXUY+gq,sƔq[!,>s S__J$%(b ꜋z0:vTWM#;Dئ cPRw{O]ﶪjG'!_ž}a 'F,6h;}mQw)vnu>m*;y} 0Ir+1X[P׉Ά%s/>5+4 źֽXXx]FXtMBĉOUuj]^01 6uL#HOxŸ= D:QRw$T ˩3Ԝ@i%H݇:چ&46v݁}t7Pj=>M5XNбUR tr!6%ǎ>عc|9S3A h!+q;,@]TR-n򪜴n(d"H>K 2BO;qw?ڣ'1(-;\~ا߬Ɇ2y]A$"lеȁέKhCCV)DtEK#UW>o,W妌ק4H" a[CjہM~S׵NDtu%Ƌx*W|DjU `rti;?v%c L ZO-B gp*[G nS-F[cw\CHOT؊95ٕ`$5E*g2YNmXFIsC\1rF@qQZ͂DNr_N Kqn}bcgG]Bfm1(VSu#zJU1g@"I Ձ4CS:CDwd1ʋ:+hJC81uHzŖq+NUz $^^ԥ[~v7%ӹhQ]u>|,B%UA\&nOh=ڼ\㷛1Ok̖żcNN$Ish 68}"9){;\% n "ӻGG"7R /FW46)jM߲O RQѨ|OG)` 2lF4KѨ>Z~ $U=,ȁF:`m}J(%<RJrA;քcq`@d-7"!ǔ"Vr ~20 ;2j_ˋ2r5RJ5Qc so*pf*\; EZKޖ ZAqKGI)ei#,:&De\d)<%}o?",b~ϓS\S Y<8/Hne [7lgr1P kN b `|c{]} })e|c5%(?Dg Z݈:^ B<6^<0#WzUq^kɠo~+(ۇ1Z`\8I̻LvKyA=db\Op%H9.R|"֩t ]-ͮRnp}ݮ\_.tb7Q HTLPRT*ќMF-jSä 8g/|=PP#&%vrI_>,TڱHZ"(4˂xvrcn󡱶^+Em1vΪ]@flS@baʚ f5(75CnHAnTݜqY#22ft"@&ݑ{@a6C̚2&JgT!)Cj4ㄮsۯsվ({,^x  ktsi=R݊2o#7>рjx 葙w7ɟ($eaS{M[GPk8:+Η\mn+{jAD˔ZO;u&AaB~TC@&ᐓNy>s߭M+H綺Wh߯ed~dSm-Ķ4A/ w8R֖uN&jVb"4\t٠J jMU˵Zs MoSnh1[vsbu{ hH_e ֳd% 7{}}!D}z|ɞ8Lq j1)[v_Ts3ixM>|rm߬+ӣC.+చM L{vZHMB v劲2@|"L=rR%^aCf+ʤ8q Yn-mw"vp7ٗt`x#l1)>\\ Bn+H4& yCuDn]CSZvzߗ(R{YR\q}w&$>46i7|6x#r ƴ툎מQs\`@ɩZ;L-vaޛocަvk^D1:?M3R['~o#$|ɅGI-i &S%[&ImyRQgU N(rf{ } ɒrmeOvuhڥ;AЭ- #7جvgV[uș˔"TߐKX0SZiLtT^ b'v4qv𴂫dJ:[MG6 hӭJq5 ε7|P] λ{SҘ3t٢xrج˻ask=,&0)i7L9οptqTlٺl߭jaӪݍsY6;T{ğ=^Fr .V0ϷQ(uAdu̓ .pDʅ>*3Ձ=𧥧$ٹ! [!"Ik#YQ1":Y*)HNB=xX̩`smD/0s']i|w`p80GVɟ薘$NB5M 8ׇ #@ C_ʱnA "< )8ٳ!'::[̕@_V׋bI_h4ID2yoE8ۊB;VW`~6]ßB)` ](@L-lGT@$Wrn=`l*6ȧ3mGݘO)X!>bSP*42WF}C7/~̥7~(RkaL:ub׳x,KxrG=V&/Wh_cP2{OFNPM=ߎ .:7e3u PTFR~ !Ƴyͣ /(xYmd^Z#θgb6s4? "jl`>4k~>1xa_ɑD6˜lrd}rD&^5 F dzcmӂ3.̭} σQWv[D}HRH)ZG),e1 ŏAFr߽TS8dg虨9YtaI uK<* il%uN*hO q!Pl}q:hOA?i肒ZfXzw<|; p--t?!7"Lf!kvsD9e[l]mukyֹ'i.y}ш|a<ӅllatMYFEu4R %pʵwUwWOQyk$.svͅ}3U講Rc^P1hbmׅ2+ȝCES󜯱N(pԾw%f 纅EUt%ыnP6aF;*z΃ml؎뚲q^׉vZ z~hIbP]@jʓNdm:K/: *Cď36B*N)4Žy Up}=sVeѵiU{=3J{텎!:{g\DiD^t;DX8Z  b+A谅V OmBѹimokP{ M VB.)4Ӝ{Jzы8i+*eHɼu?<9_jHmo)ޔZ]C l(Ǵ g*JřJ/:0z:3FH5uDQ ?o7+l^cuO/w~pWjt-NꪋSRݲE+\0_SjD-OĊ)Ln.IKeN 7;VK~TKb/Z Uh7m港$z(+UPaFv1س8ut )U ~5 3Wn'v4kpx~kkGMO޾ߕ$#]HԢco#(~}oóp,et ؃۴c>'(䕁~JM\RR6ҋd= 1Mv< GWrddѣ"avqG`먋7{.%R]y+K)Eyw8".y쏝=~'#81B."}ph0v#? 8by g\PȦ]y. ӔVzR3#%T/'<1.ə^xWK ǏY6gHL%n:ޔ5%w v Zt`-%c VؿȻ7T/;\t*x̾~ժ{p%R.]4w[`mpfO2fSwRVyKH+:n1j^ 22aVWsVbtm]=Vb]oytV幋gHFD{ˀW~*TK6@#r'WN/URT)IzJ|DŽd?\>1\irY*\LuRiY .;XV6hDRjP:IUuY7J٠pЋzP\ʑ`І\{vΛIA hHC=SN B>w8a@I=ZR&TaWW+"j+?d39ag68C -sXMH&(wܺJvG|I,Qt8 Ƃ~s"Atl1>jR4DFtBio[\MN:DWhp;u9CWe>+4|BiL܂ zcܒ[M ΕsͷJ}(V,:u{Ƨ zx_8wps6~.Q%\ns{1DO IxewS!,} Rף-zi}a0x$lCder!ME(@͂ȱr{E3"o(4WI FnVbmu9c--Nc +ѵuJ팚uV&9Gpw@Ta{GGnfC$&ĄKI$`N@Sģ7AND=Nywz*ˌI^MvCHџ:79<$@]_D{6ܖ[sH,**k=%D_,`:p:Ur;t3Ֆ]ѷcrH}Fz~]!JC'}JZ଩ _X , ?ܲv>Mt(5}5dCi\F<}~ =:nMi]tWw gAb\0_JbqYWIt0Z_vZ2(<#$_e$fI1I*b/nX!r_(kĶ^nͪP<7iT`TVWm6ӰqDP*+Rzd:1 !F2RjN.7Z#EGOIJ^վe;=/-x2gQWuyV(R/zX=˛%ww~MWu:EQI.T@\FCe2;a򬺐o$p/m"f4$i̴™"],:pR~voOfH3$"%eq/T^ۄZ9G14蜴KEYtFَ8iμ ij-uUwV;:ZY4ViWK6l(+Ӌ}0=\s@]*֢TX2\^ O\:'%5RUSi|ߢ8INp?7 J zŐ_g. cNDF} N( }Es,)щGx2|=T^R:/9 {%[9I% %Nu6蠵&)z h{ʰԍH4(/z7\RFwO1.":k-:%&m Hh9._ձy̝/&1^5_OH%=#*RP"?#m/ַBlG)eaWTjoY+ga,QNl"B^V߾#OoqazQܲU3^KQf8iܓSXu7%=۶No)ҫfv繊n\qyQs5Rf%yKc Jbru^_=lPʴtlwSOs@j.7( J" \hJ3d+]\ cdxlt6>%ӒyM)Kt6Н<$ a;kz"hn#՚R]߳Ŀ26bz`H?ؕ=)qYydlݻOws`Zk?dV c^b5*YnĊn\~]g7壬氥{팑)\wT]tu|]w?GNȹRXCH7scPh']'):~dd^~rT$Ƹ6i;C&xU#uUg7q@H#!E?#dtL5GvN…eSqB6j;X $ Es,0e#!6{.]R'EmV쵏0R1Ȳ.#F~BUGϕ> fƉ4}dCGgYiDBH+w7ϒϿZblY:g߶>yg%5h 9Mq a,Mxƈfv.pieyR D?$o)ΐ]@)fb=d)4Zbi~w9r;fZYx O?sӃ`e$3lubFqѱ?VIg'ZO9kg\V-YDGMD]dY/zJGt:Nks,|( B*D|!KUs-lJ~*.(~Ũ`lh!>J2aeFv5^2"n55rT/Wut6knRɳjfgNO9U#e0VH%:oH+[ 9ҺP)cށ@oX# NWǃ$ !ϼ$4*ꍫZcDeYLW<3NlR=$PD .!jW. Z2 fNAŃv͉7N@o{Ym 6%Rׇy%ydܻP! VВ::gC<"4if g[G֨ϼVP #PJ9G%Sq4wG$@/vCkg_!NCq]Lhq< / jqUCdcK0{5uyl[ڷ3> (/}^i ң' z7H԰o'nl1ei9*+([̫.^t+)_P/O!IZ2^7ى|M}/ivEYeZ[uaEGFٸދirRUH1;ԞďΕ^]S.3}D 0&UO͋El =xxλ)AH.B/ͥ2=v=%"4 JPkN#Q>m瘘n8tt01 TJ*;fs*$/g-cKO*u2nR@BYrlPfk ],~yX]pHSm2ۧb%DT',6TI:'B҂n{B]2X<-bCKm4rd͢kwl͚v]ra$."j.Sf&߸3k.n0j P}qE%꒐c+Ir~2iua=3ɡ+lڰdi 7.b0Ot!Q| #T]ׯz[Eٮ"|-/Pyg~ύamm൶,HXsŨsNl# vb4}w6& [W䫞Lht&Kπ=ӎ}-|_V[閴/K)zQMaԕyDOύ< J9 Ǧ -4o ҼJ[gow.,4cѻ-.-4ͺ؆oI e)fpa!VJ9YGG"lv@9jdEm7@mF=,%պ1gl||56c2Dk]>k˒ל~cGoGGǪ4]GGCb*"gVd BuyL}@Me^(+p'Rw&= )WPg+2A5[.w&^iq}f=ȀSnDhm5 cEGW׀B=7}S nz6X0{l$).-#Fi?p䭊8ȅvb;EطZy/RQPdsދPq\ @@|QMO܌7͌`'E8ruyh5B2qPX7 @މ (.=OH M} xcf3lũ抴sP^ѼxEAid yiA+gmXbP svƛĤDZkEY_m.T;--,82R+}5sQ9;ꛋ!hM+Zt"wD1 YDsZ?n3/[W5x9{!]9;J~ b0gˮ'*QqRZ]M-H i>ҏ?*Ҕ"_PiBu^W91hcHֶ*9 -T> S}ܕ\U7U8{Ts6{^#sҕ!;1C],D>u%!_6*ػ itu4LG}lz&1QV˼'\m7eG,W< MOBÎS`! gbCp#5 T[|erSI š}Hhz8f-yKԏQ`LA;'|1U4B:c$VaȜB\Ky2R3\n}ӻҁA: !;C B^F|)8,#i2ڶ6$(Jv4^{}^>C,sf]Af9ɤ{uCb8= 9~Phpp10`X{%Qݚ)tA4h94f!-?͟#杭Q+(5@Q8Cn`ӏG/Z(_߅v;Xd%ha|x)͉!_*!SVsgU-ְ\5fՊ6/=gy[BEN'YM~=1_ɴU{z:qSPmmi &rN * hJg>dl7gVu=ہ;k1HX0'|͕WN:Hi]U$,s٧>!\B,n 2 #4\ |xI 3H6%"BόL! LHֻ'WԚh7 OdrVer517b L,wXlw>#0{hRdms}@(!M p>F?SeNuj6L"'ga!!̻w4_CJa4vND֞Ƀ]Gti= O{R" lcES7 #8~j6J5YA.:ABvUdmr)?#],;]yvE$]wހy\hNK'^;(n@` {>v y="d _P F";95a^6_Qn>_zT׉6nr\>],sq¬Ļ2/9آv(S;rw666W=jW*ךnlG.l55g+,UA4kjA<3}pcsD{/Ɠݽ Q5υP4xzyL%pS1nyO;lS1`DhEI e;E/;:h΅ ?cJYuj/\DY:KɁ4b.0jT[).^(^J&,{iѺ>E1:tuU:q򚙵A{TK;^B ,dnr]o}7Rr~ca7i+Hܞ.K B&{qLB,+ɎQ|5H

}%H(|QK(sNC2HhVzݕgМFlZГšb7Evi B^WFU6QKAlV} )L.བI,VNbZIx(_ehƫ]} y8C`GYG.v#2Bahz8,s{F&|i,s@&4,%.#ڗh/jlM\"6:l:f8+qBIT^EMs?^2 "_r@ sxn>DIu62 NL=jw%gE)FvO- sB`K&j98܊ AٜʱpܐO '0<` -94lȃ|DUXaɅbҊh}]Xǘ*Ig%B"f\`Hk]5 Ye^~aA:[gD{z* v*#pE&e7=L]֔_P{USB`OE $-XHS"E[w&Nn]>ԱGk6Cd>*OmjVǁlTO]',sQ(խu̓+𮊜a )Ehا~T]`ki,J Jn^NٕHAN3l@tN]l۶Mdk~^7DDp[ ݎWj(6VπL#7B ;$(wOu^4p !y֮y(dAۻLj[U"؃xxb*PhE=|^YS^cOz!ӫ̅" .kK`&.'/5pn+cDل )kB׹@-v~6 7!܃W @44ti4"{E̬ "^_vg._ڍeb͓ͬbt2N>T2n/$鉎kL*-d(P~fJe赯erJ϶L' IF' rMKVԺiH\Pٓ$֎U#m5㚍'pn eb٪h 3㢲;P@ԞChƭ:KxbjrH[׵YWS(Ǥᖷ_w:?H8 `QW $Ρld,WOk!v,W?9ku:f+*&rjI%c=Z-} s;-B%͵ 2rmu)0wTyqSBNl}}er%X,@}c=VZFO) QirL\ X52$6Cq.IEjw>{K>Ļ皅oC|u!ZռMڻ!rXuU tqcP*19RZᶥ[]lng 'xBa"!^[-^| -^zI0vվs":wIЭ2=" i6Vպ@0k A-2DSw=g{5e5>KW8G0WXޭ]hZǎyyj^yI2h|@ݽlL1:.ɴ]u[@o{.XA>6K!䮥X}TM$%ޯ ekdlA^DOWD`{?5;Fr=_Y9rvgFr76pFҩ*3hD=Wsqz!UוvjXG&{X*q>8\l緺zqRXJ}'c6Ӯ F΀>g)ȁIv owƀ*6'dEuݵ΅Ye;~|RέpgX5F騾VMLYû[} HئÏ@3~%t71!`iR%ح?=e5 5^H \TcXFe-3/m9Z;eDC4\Q4g&>%CO s^aߚ={*ML(xQ}1,g 5}*SG80C:a \W֍pmf\L]qBp(gx܋(6y{dTW-.w3һ9B>ҜG-2Rv> /$d7r}o;fԔ}k~J.Hb/x\ z]/ҜBg8JFp=xBS+fZ!^15VT{OrcN 12?3y@eT -iFp`jƖ#_]'nN1 0zXg`Εj8mFR}3u>g*C`pqU| Xn y2s*L9BcEVDj% gɈ^fU4_$` g|SgK%W6۰fb б;Q!jfX"vPLsIbfLRX Vā xk.TcL -iJ$- z,=rIxIo]ezlP2h'RZzW/AY(,bOItt4 k>wJp݉3sGA֧|S]g赿T9lIv9yS4ֺ"BsfZHWyNbOhbF}S0yp,v c@?^檕Z R0hf뼇f@1$2Df(PV$cۀ>"fL2):xGեvYs\z],Q8:u2"\ړ"_Ls˒B[qϭSP4@fv2`@,&Ы^-otZhZ-Kv9nNzs;Η.`UC;:ByHӄztOۣ&-rڣڪiE`I,v/mzeޛV\5Ur;owgWkn !l3{)ݘnjT ܨ_|mtjF.ymy"9֗Pgu__NMX*%/I!g0x7EFhZm3%+hyB!"!m=Q.5+vԠAwd[AѭA&=mȠ{Y6dН8}jKnCtnAtN)nAW ݂t' fߋ/ h?.?n=CR]~qdcN)fDyԓ ؒ⻡+N)BϠ7MLt=%n^W@#*.)хwG{zQ=& OPN).z ewGTN)e@u:8]twtO>JEDƽ- 螊feKΠ?Dy񺆠DA<"{5]pOtO5נS >i}: Z}_A}=]nRW攂r3G=-Av{͠l\DÈb3G}N)4NaDZ UwKKQS.ѥvCof: EW}=XtQD- CAn +КPמiҟcɅf;+|ʂc%{F)iFtݩ}j{<tQ/Om.BR:Ϻj^Bo~AZeZ}bF)e]GRГS9肏>FgzRtU~P|QoQ {9z" u-%5Ḩ5S[Ht~@~%w>;lEgѽ]6mPRݷt =נ >:n/yV[n7æ-ER|Ht"E}x)ARݳDOLcF)^Y޴?&_.obsPD+͛z:~e}5JAtrlQ {â.]ݧ(lQR(};;ָQ {U1;x{E&6m+(=uw(ŷ7;>~^6m1T=nkaD' O ޣF)~~wԧDE~߃F)Mlt{Q.}= : qJz@t@i`wݓ,ru/%Dw=qݓ,릭Pݏ,^yǷC:BE]u*E@t?>MOm[Dldy/DwޢF)E͢./|>!tH;JaDw]uDtz]{nԉ(.Y  Q{E_wA* .lD.C~[(A! t]#3IQ>,5vBD/ݥu %D~= CVWл=\E/9C~RZQ$Q'CP袮/JAG/|G7_ڤ 6JiD'MWQ7 =̮(~i3;=!: t{QR>Dn/]r~FgDM[AG)}s٪!h^xqS֣Nt@ 7JQW 7~ޥoNtE٬߉]7JYy٪;;uw(A~E`'!Ptݴś)Dw]]߿[L;EE]8J}wO;_˻~تl>wd}3[߉0:S[l4Nt@PfQ??꨻w߳~eޖ +@4nM-OGdmp33z$k#ˈeR<2b_wзůO1|/VlT)~4|'X[x7m6_n"U)j~'(VwJl@]^łlڈ ]nT)ʮ*''mD=wxU^]Fp&UU)|'oB[u$w] ߷*ŋR== ˈ~!w*Ū ]F;jW)$߉ aoUpNt]_(eNtRHU轡=+JQ`R'ztE{UЫ^<]zr+JqJbMtQ|tw"DO=|1vK.߉~*]r*ECO}~oCM|e@'sUU)vi)7IC[XuNtct -0߉n"oz^C2ԡKW3Jnڈ]][4m)Gm5Ѓ_g'=M1|_=̏gܯ[£DE]tGs<|':'tX`DCz~s^`7|:ѵ=_7[)Nt5|&-`UԉCY/߉~*Їn՗u|8=*ȣy3wkAO1sԖJ4tZw|8]<ꂾ*`Z.+iM|_v Է8=۩] ۪ yV)dR' A?>%J统ԉ=,{_U ԉ*仝ԉMC? wzBt=QGT}KtE~wQ[r5㣇o :JNDWnxi#&V}& N.߉ =YobY>Ntgֳ'^mڈMQX7Hs\oڈ {;]<7t Yp:5zR}Z]l}RȦND._p:UtmNt?ޓ=V RN6mDwboM5|&:V ~w;uFVwkAw1n8ODׅ> ||ǫD׀Vru{i#z\tyfY.M5cߠ|O\] >+JaѻrDW6复=>QenR'V:sϦD׎~@]'ukAOeRTYoR'zCt*E;{滟ԉ}2BW)^nFt*ԉ}oM|'􉠏 W˾YIBt*lڈwԉ}2FW)[7I>k>aolI 'сN+@ߣ~&|mF]_e}Ft&eԉ%t.o~??~\|'ntܷ}iJtoooڈݠmiׁ~:j;&ѯ7[.g5㾥_+D׎^}qh_aUoڈWh}6%7 nFt*ݴ:ѵêmڈ~o7WRdDtT)n]?:Ja7mvR'ztط.߉mLX M:Q麦+ker%sd39=*ŖB@?mC] /[PGGU)f?-a |::B@U)އ??:l݆a9OB@1@U Wڢ::~0aU﷡.t fB@-w-߅N:,ۇ63ê.tt7^,_B)aU:zT|m UXm T. C]v,k#ttT]*E=NZ|΁?zk΁*lU0c^TvP:zd@U}eI=,::~SB'AGm* usR5B'A.WmU ݁kVE"t7amN$4IGP.: -G+UυNRL3q*tZ_eBgAbP!Ss{: JYa: :~co =b l4[NRi[ЁS tKsӠê6: *Ӡnϵ?=Mu]C|>azզt0]nԹwrzzڱu>/wOxk/n`b4l35Xi[G"E6Y,y[sϡ=+/*Ns<ͲC.M;Jr8;bMf|wf[zL]J]~ymΣPT."* 0zziX fs%(uM!ݭC6ndr`n~ٺ6J}=2?DFeQ>/Nh$d=,[S_Iy5m2v[|{}lHݎ@fiWMIENDB`pydantic-pydantic-ba0aa01/docs/logos/nsa_logo.png000066400000000000000000001460551517143232300222030ustar00rootroot00000000000000PNG  IHDR/PLTE3201455554455355ܤ=Dqi<5{Գ9k=h;uCm>p@wDrAzEݦީ&ܤۢ߬,2ޭ6Et=v3z 8x  Br+(򞝝4!  Az^5HII?tc8 Dx:5%7h/!f:0 '`7D1pO-fH)@-[5:)1;o-aD'.yV1}Y2///=d1cO8T;!}}}J4}GkL+'''\A%;RuS/ЊBBBpppOPO >n;;;555vvvX>"Fmccc2buAp'Kiek3iiiUUUٟZZZIp9Z>[{˖e2+BVQݨn4E֖:GOêq7υר8ҍo;9WkTND`Q@mARDAQJq#esQ_w?ƺ9cRJ9c:;Ú b@ {N6,<m~Fy˚O`q>/wUco!U@qsy6ƲTW2.UÈB<Q]i8WݷaoQ\ZXtGcaόZ0emZ4 -PY"*xh1Ht3dsE$Ȃ(n?G,g=y{ΜiPM?ox2¿SGd?4;Un97ڕfM;32k4OG~f6 8C<.%<{5D'\4j!^/O|Wsߵ'%]otܖv_X Y/jbrA+.n~r5EwxP*Q+7$Á2^d8$(5}s׭ͼ\ߌ2(ќ$kY&$t"d[Z :%01U%9?~}Y-gw72d֨b %߱NT(Mģ׺7'\ɽg{J?ջCic#4#/׀!;U3/[]}-@"kr<_6r]ە}K.ܭS?J Q2նQ4,0#D2|.#*$O9vW|#'{XC/0eM/1).32< 6WW>G끈UZ N7P1m~N5wx㔗d <#:*z&rp=-:'kSc/ѨGvڱ3ݛo &4~=kDGIu.´81۾i{:&n%Wa8RSWh!"iM#I?Q FPQ"baYHvQG!!B4JH@!%5cgywTK7jϦZ;sϽHh+uӽ6}]nsrKKTu6z䘎 cQ) iBtu߱OGD>tN97gז!= ё=X(G͸TƑ(3 hgŇCG -ˊ9|uZ 0h/1P{/߰1yUtoV@u=UF1׈VH;xKQ[Y%H鎁sűU;i.Klς%4Yz24sEX5}hrlq(X&ؗtwo؜=b\G +%4b:ֆrDD- 0N\-sk zRt/[XC}sn9 0\];?}y$OD<0```JB=.[0%݌51Sdh++zpECP~0xrd_m]#9^}hxL/=DɘܥZP<ÉBq ͂(&)x|ֽg&,GZ͝?9i[5۲R5Ioˊ z$cVTi'@Bb߂ J=I ϐ[\F||'TqF+i#r|+ % ) I%[1b$;cˮCMʩH݄*B+Rc3Q*-isGǃh^>};VCb=`J_I7<(][yapɩEYcǷ'>B$`Ѧ,PAY\[2Qo(1T)uں(Mɰst*/TOO=t2"CkV>*{mgVW?4w޲EE",7#9ͽ3Io9`g݂==n'(= 0̎͠6j_K:bدcp 9* F2J *sSI=+uA&D F]3?F*nuF+d$ #R J̉iN8Xhl6cj~}pfq!/G3MJM&`T^`/~;ltmdod3BOWPC UQ #!Nb+fV}`ǠngGtѠ>%n>n}uwLi5w) Wt´qsAiz"Y/Bꮟu;\yFV=I>.Ým^nsﹹnY%DcXK5n>d29f(5=e`]5j_y,o\==7PY9DOL_][H[g_wB9kP e4$`tbUTKZlT-.M &iNs1?ZPo3j=/p,kuBsd:61VkCz<x<^>YRCl}i{B`wf:9ǮIL(m./AŸ//2|#.0벪{H8?Ñ^pkMmuy缐~zG>"p9#߻E3&8*B Sк[>jL_Y<Y^UwNsa,~0= mT*9?fsJ F#}uC)uy=x!a0Pv\ڬ )Cf&_3 5%? E4H)8gR١QU9㶪@%*_C~j4Wsar`]5\Xgje( ҹL*^9t N=ڳ:8ipwVdwgSUT#73ok yx^(M LO/)JPUqݞM:S[lsL\xUkߡQH [@0eoo]W8pLĄk-`x_ JSiWP~K9R Sͯ3g֍,).ʇM}4Gw5H3tn;OƩBfƌ(؟=<2i;ٯBf/ iX] ^#M^g ~IuuIPQ.3"\sHyMa&wt|U*Ç" ->rk٩!o[ojbMzjU(^HۡxĹT7KοeR2M9Al'A vK=6ԑ!&9e+Ŵgi PH)=g(]` N;Ssz®qҿrD,4tZKNkDjS?c19WtI$TKvQV WgoCO)@ Z9iqd2ƚ{r! HI,SLb8%jSZyŵE "SRP/B\HIiLg5I4Q9]'(Tra Z8bI{ Aas՟$pf0+A-|RW4y5 b*4Y#oRǕyYYs5uYc^DZLl\N@hALSo"Gt_Z/UioF@tޢXQ:W&ad=rxy&jѩ1' Vgk7zڀ1-Ec̽2I >*ysR@gB^jT-]6y)J#AGvUƳΏ:9Ԧ"6\2IMG(@ GY=wKz&>([ڌF4 q&^~_4Z@M9)#(iW[ձs߃jBsW_5-˯1k% 0=r*3rvx$E`9"{ ,6B݅o# C+)CXihC7e%Oө>/L,*nrdP3߉hA۩^O0(giz۷"n;<8< * 5-F/#ĔVc}.NŴإim>tbhXgi&?7Sdh? +y(ֳw2r 1Ҍ`yaJaN_<- eZ0'B{b#:w=M7x!Ή 6,CiKٌ1uA5ݜ]M07jtaD{׆5;M ae0O@;S 3 '2]#^/ZqۋE1NkA$:l1rP$PMfٞ;iЖGTdnԊ 6f^bPmGX`4z#X_f]h}/fzlAKaw^" ~4LjyFl9mAc) u1)Y+#XCv{X'‚xu֜1ګﷶ N|6ܸXR- ~F '&>R_M'#ǢAHZ ӈcYD/:}jR[TO L)T%vIIm袷Q3 . X|GgWlWi" A"ciAN' FWvc8=,&'$> K7O}JX՞yZK G;MI]a6׵ܹdollKw[50#q|1 ;~_嫵[ZŜ{v3T˩|ߵoGǏ**`˺ޑ*?;G &␄1of89;G?۟?-o?%wEzE=(-%z|I:w>1y6@ۍ M]յ=sȹ0s oxۏZ;Y/+zJO#RQxGDsrD_x{{g{d8YWWv,*z|}qoCdJD6mG6Bu c_;wq> g8)a~>hv{;T5f@wߒ?ݩ92ȧۊ.g`pǫ,g o$+n7wa꯿vA]Q̼e4|dI;i-^ l\BV,~TjcH9G-ݽspUsu .g7INޅlA1I߉P]qަSjIpP|/_M9IFX?:e"^ F_8R3MVˁȼn@ܼv+1+ZtG r0ڕUEK !oV2 S@*42X a@RR*1nT+.U֠Blqш%*.MkޛfܙswYALKR!psι[ܑw(qVEqkyhC]"G ,Wbs} ιZdɪd!]twIlDX2Dgx'97 wuo|Rjxdxˌ5xpE\xXKW>syvĬt..s`P[dc*:Y?kZ~k}cBJD/UeEttx1=Jyrs#:>#,]Ii}eup`]sl4/^8(.|SMk bU 6b,!AXre\ٹd{_ykIaWsLiG%̰ʾh T&><<}ܹ{2[vICtmpSf8͇`t˸ד̊f6*Б#S+1OV<9x#rVUvH_.rtJ@qk['Z GMgsZ{s#^Gͧn0j{i%j~`.y#DlK7oH???díGKR좝WD5F:xx_=);]x#(4|=ۛ BM:.k=XrM#[tx2\cy"(OaZ*t{ ^>?|N !/w:qHLu :d t~]hf!|ukTʋwDCw$ճ!(.{e:e΄鮋뇟ӡaqp;_ΘZůܟ|'GnڌUx?1swݭj؝"1nyl\ƈH(W9=vtEhƌ\7o(yj@G=zU %F/7/| O#3Ro yM.W63h<@쬠@٧uiXK5>ȈkxGOEy .,瞣ҹ(<]Bycׇ?Ya._<:bDcsOtItA)WmhI9h[@N$JcKQ.۰_~ʈ].g@rtHLW{⵫?dw~8Chc,~]B"]Jm5Sd&Ǒa mkYcN|C{ jژ`qrҹiF5]_C鷖db :):;[*Q$eJ"ر^nV7u@/l̆#t>y>vZ瑛~qdR0S(Y2ctd1qp3|G=ät/[š#*~⢷0ő2ǃ QN}Ad]qW*i3չa}zgt3i֝9YQ.J?X 'ʊuh&%qIE$YW=ppl|Ǒ _|r>K4 ETMt5Gztu݈E41 Esܱ:HU< j}]Cƥkx2$PX.:Dfu{qݷԘS%?Qzҭ'4Uik 79Ԡ aYqahʛcES?fCYRfyAAJ^/[ d=4(gLk_-"TdlO-OA/slc(59a xu0uՏw$i(HiYxDT|ۉ_E=ã9/]˛V߱}<+ SJ"V_M2I^ o ӱcSW@5r:;¸Su$hpGB6P<:&(!]qȕ\ly55`$ꉔ^h\) k#TѦ+[FvE;SL5LCN;(Z*(!)gG"}̣^P MlpV4몪Z@͢yQm|bvF+C&v+7E_ :{ZD5#>v&qPo&;Qj6MOLޡm'76*"ӹ?~f2tē-difS73d 9JG~[+y0tQc()nKjQA'fK~(KԐ_~ex3YM3\Hxz`_ݾo\ݖ$rm~b:U{wVyt.=A]S/q J%6J9t_75]{e%08]kTZo#y$/pH(H^ `PO:ǜm!y1mQ/bgא$2 cX]&-,:T.2BP.(&bӻNOluOE1 ?oen~!K;5@'Du`X ] !xlRDʎ IBaǹSn]ѦWM8 QUI6U8Xl~ MSupxnsiW"xX$Ao%$g/ k H*!%/xcCje3߉B{i/FKKR_}N|MցT] {9Im(Ưj_B׽.=$ϯ89]Noii#0 MDE޹u|0B,Ɉn9+E]t7ۣWU'+u;8CI%v&[|72ϴBŠ;V?{^%^b5?jQ֗)ydRM]jm1La< sy>|= .SSd`/7s:}kvɦ>Po[: єYحlW^d(Ko-\%! )I%9ihWZ&yު2O\dG2*},E.%5þ$o +ŵ,Q% Kܓ&\Xe &ȡv {wLhݛ.l{)kW]&ްeK@&jM*; ZjlPD"E_n)w4r)4'^}Ɣnf1E4 lHӨ^ؓ.kktV%l!?8=ȥ]I ۖnN+٨p[f0uq9GzG3#Cy5a<1 =>G!@bqRB!Y=4$6)iFE v7^ ;їz'/ dmmo?b5%Sp{akN;:h*"[xNtQΨO(/3 Jb6mTUʆt$(U!#[wy(ûs%3A~jmnQ;$6Yz&,i!^Ee8(Ls>QhŪXJV&R+PW,ûӄ[]._AÂ5wel@i\e6|C=\ƘGI.1سL YdnAa׮G2.)' S H_ɣ=Ȣ*siwݛuwZ=lryo8Afe5t7c3v c F`r{5ZYyџ=5Z#y ^ʹJ:WXF&Ψw\qð\55+VB@@!e@$KF/Mw\8$ym6疮L'o8JaW6 'ʀ-ZMST/MU L<6.ƩMcQ#F+gsU`5;cЮyc9 ӄ::n H )6ӻ-avKkD)HOK kO4KiBgS25p\Քp5 ѸUd"OExsP:WT<7SLS4nYS(]O;0Gsx@ߏF7BX `::!ӻCq۲A7 8"iͭ'CGm6:TUGe{ +,݀ 3IJ=Ew?x8wv$hn؎PF '*63,rɄ&F{ȵ1#/1Sm AQ8eJf!Yl|p.XS5nLxf)wµg&|[;+9SU&^@w %z% .ZBY]5s * FPRB( *OmllyukE(~3wiNkI6nlcW,dqӵ 5.;M1+XljzjJyƴd)G`v0lHkqxj}:w8ժw5}tsyj(31]|&#pS}V۪r-p^kRj)?i]30^JB֥a÷oiB}Wix 6UW(ݦޗޑŽ}6G+wč0;SUe/s02;I^(B y d}~ 4ݫWScgxLW*QsB8z Uev['Yd,6z]EU!=!{&S SvƢjl֚e<#A3 dttε fGC(}1Mkj=TӃ2wߴ*CCq-Om~LJvgbUW@!qrqAo,UζYO9=kRU:dm^VoLE=~ eOp;a<l|#a tѪ*aCS|-]nk[vjjikSaI|V;&Ӭk*>B_+F i=Z lS}'&M tҩ uYZ =KUkA(甂ޭc$];Ϝ5zs11bȯF 8p&n( (`5OM_ۼ:TBRlnX␥/]~όUci$wyTDbu*DSR~۷-y]H 3nzM x) e Zi搕uUfua;O0ûzs_YZvhG]Rzێﰳ:I&>x,P ^ FhWKvlLXVo{/|g~/T'^)v1MQ8vW{⇐REҪe݆`LTQè}DN "Dbb An{ΌWz1o~}9}6o?|GS MɱȻ'N}Ȥ]nX1&8\VkV vNC+vpywg%eEküƁ{wZIdQ9lIV"iѕ?iw> \o5#/`ZM`;]Q?.Sۢ3b,5,S1Nܢ3dwkq}*ֹ7~58C;nHHsF̒ݴ4%\hSjb*.聸V廡efb}gI5hCW~ uOR4FcׄFGn3P4"9vZ^`y N̩Al9H r)u O:+^ klɓ# lqjQbf♳gG# Ubr0-(m͍"=^MZc|B}.ܓ[ 3zh2li_Q}F +ढ़;Po&1!Kʄt8w5(drs2H**<'bDsqfWco Z ~#4<'lA?ΡRsd:5fM<,nA.cO{0:kZ?^#܁LG9-l^!bsO;Le.>Ue$@7Q¹!3]CPJcF\CVsC$2T1{V[ÕE)c ; G:~_xEz]ow2f@Uzu*bJj( kU1Tп'=4<5`:=eoxqCPQ ]fb@PڢsA%vwFߵ]{A%79e-ʃ .>AgwR^nYN.wLai1ݖ"JN Tػ`茵{5s9)ӷowpl|]oԫ5Uxl![/^Ü>4B'B] t``._cx&s(lә&*k*6\crS+7O}X!P=oZzg^n*sw佒V97E&lR& ?AJSOSShcwrD;.cګvDjr\V0Ogk R*ﺘHoWbXQwh'vS xlmxl^W3U F߈i-Kge:j6w:qTp%vQjqyi'`VO7oA ƣNJ}%m3.{@8FnA>;yY֬t3{A~;)#'ۡ9MFyC5Z&r"dG AQnsX)%GD)Shf4,+ny^C=E x834LFSm.Y֊C\gYu8j\t(Tgf|7ХDS .˪cq-!8"Pee# ul!09`ѳ!ޯG xxJ)Y0LAHBr3wlbnuhnpò}%[ku&4S w(?mט[Î䵬*?w./HgMe΍陹ψ3~>.HU8] $h>wĉDP2ՑÚlX4یy˕^|UtX H+.(Ib4C{?(I/1 W鹛iKUzCO=eSk8I(1<单/Ud-z)9suri@?ؐ7Q!NH>5oH ; ?4.LH%W5zL?T _y@z3SwϤXVjvl8,cmP3O]qr69u1$\F#86#@Fat"is sPN/Wk7n5ƣ#Dm6w˺0u_uG_}N=ƻAM1ض0FJkڃ!p!IRh<|I翪*cB}dRSa~&pSyW[n=tzfiP38ҏn7[hzP0 3t_8nMpJXOz$V󡂡'5)6g4Ghٔ#zTY`kr΀ކELXPޗFu643GKߡ Vƕ!]7 rD+;ҍ6w؝>d::ehe*NlKRKy%3s@j)Kb*(yE njl~G"ʷ^[Hlba)m1jw[ӬJ4Ŧm^V V繶trtQ%KzіVYZ* UWW:pU Ļ.yʈVuX!xi݃b3;тb.O3O>3_HOE@Vd$ 󑚵C zV[~.)U" 6碂g"O!z\zuB\ w5y1]܆KV]= wmdzfHaSGzӻR*HH v-3A8q]zF[j&#wb.n}e-r>!>[4;J.F:qmW3P;x&A3%z 龁e/_%W;&$S$3Aa|:_䡃~z3\Tlpje)Ϙ`GYxg;aY8:\w=\qn->2:wD8z\IYy5nPo+Cvg9@D:x|_?>ߍo}|]YIΰqLS.s&H߹ ǸƵ_ ToCyݳ"tU YJst9c@@hS-`P2>z dlu/烺먓͒_ƣjU;&@-傍3x*u;"d^ABW{,u)H3U1NN"Re]gt6tq$iC_Ͽг7y㹥'!II=7ʕm6x :awa,*yXʞ$wNWm.uu}{c "Ϛ AݡhA:-'tG&ݗ/{U;tYj\Z G</?ͮgq[ {m3So9+T啱Lz?r]&h!񿀾/G!aڕCԅtYN۔)鰧 O<̕lF"4oJM DFhgOlm_bT0{fEżcD6LŸ3H}ľ@K<ٰ}E~X݊͆ 8TiU7:RH5=o2o lZ|/d+y؇q]hl2}>±Ƕ;rs\y\ e:-fK #!@ .mB+1/ ]c?[fSg*jpc3IH]+28CdaAt2 ӇP|Aȓި_q֫ybG2 CttFIo2Q&mq[c\AX% S<X No5o\xvTRXH3闒+.mПW!u!~tdambĢIypǏȦ8^f7-Uu &)a\}/xo tMܴW'ShyfJ0}L:`U{fKs{>pY7j6671G?{}Wcl1\H+Ƴhs\JLSU_:)h#;o 2IƗIaUK&԰o:0bQʠ@Q󬟲YmIZbfSqͨSb 6Vs#U4!9,s(9GbJI!jhCf|$v=Sl,4k)/S@ g@ȡ{BTlKg5_v["GMJ\;3N3`:i9ʙ)Fδ]ҳ Etw?ndd'&+ɉdsiJ* Q 4\rHC۞Bݔ@cơG~ ;@XŸ @iqYqZ*YGI,cLf:xP!e⮣̩^YrXMBA:K"OA}@h<pAgSlEQgyZcyf~maӫmtu0ѳT}Bv* [_SjVn%].}YS:6D#[P/=cJky!gdt{$ PG9Qg`Ld\e՟D dU 8uH]WOljʜêU_R=,Gw9ƽh: 1f#EF Y4P(g$"a{ع_\Xctnۀy]lD6u'q ,C؍sDyUmeOP6y!++t3n42Ȩ%2,)0S1a}xE,Pe!nܱHTl`в1.LqF*+/;A.'8y╟ψ&t<:OA],Xf˶?RO2oYY?*qt2GFkwWG rD\] jULb-~8%Ԛ:ۮN}g3 7hsI)G4y1-Kɍ~>@5ۨzvXk_yef.|Zmz|TlE2. xU'nХ5ɋE)sٶJRES fhoil`zUPj ҄ݫiAWÇb lHO/|M`b%M28Ov^铇ܺFĺeU-U㢄>+CEsM9jg%8!Wn܋8qBAŻ軒y\滼-w Z( @b7fbt?Lz-ST4Gșv8` ׹bMg~IY\N*_)[]A vF]T=zli;-tʝٖC~JL#GÜ7ٮdԁЫh7:S6?xB]':ԇ//zp{6gLr,kA@낪cQO֙ h"t.c%ח[ ү>Of+vbaӶ 9][MU>@W%<<#(x<ڐ#^&1}|!G~&g^N;=Ί%M"#MRhVG}@.:\K@wXdz7CWX"fa]rz2M+|ADj T63jZi6$зy5L fpcs]HF37>^aә ޛ2{tXјzX#t~flQo/D.;̜ZJvtV݇d3Ras +Ȼց.qكa*zW2fgBW1lK|RgV-ݱ͑I$~t3(l,N>*3 ߼\)gDB#`.kuӡ> \ᢐ(aU~Ӌ8V A?c~?VZ*W2=MsʜVg[*A ;SbmE42#]뉑iD@UyweM $WH'~p+$7!0y!SuyqXhџS b/*]96Jzl")c>/UJϜ0VTY>A}j,tB.a=#}pa]u&Tu 堷γt؏眍ق8J!3(MæNHwH73 >>}w}bPa㳓&eYh,{]@jV{ mk١[q1[1RlQִmXvtR]$5]n3$ZkϠSåylb(3ug|f8?q/5(k2"O'(5犍4[s[vSBWoAaLe :mԹDbvF5)Y\3Inve(.c p?ʧ_A@,:bw9FhT ?GAuo^TUͱɂ\__A?%FZ$i5\(ԋ>,C'/Pr&ADc>u:.*Yb5ICy 1Aw8c>9c,^Kb$păUVgZHϔ3]i)әjm?;,z&S8YNy %l֙pVȏ%Yp&ReUԐ*FWKgo@*SOx̟TIY:3}y:v)֋? l; a@DЗKgO"/ntp< Q P@S+Nid-$V(#KL=t%{A[` +C7(3D?i =nr2셗Mto,##0,sbBcZ>lgLLy@_ZF L<6J`,;0-;4iUA z~杷6UC$Qdu ը*T(?;PHk/&wMV!;%{ |u7"dCJ*WqbRJvƛn,Ċܵj~E;osidHlN (<@'BD'Őiy"'_c/>V5s wV0 |V(e1ly#jѣ.!o@}$qš'qyyg :7 &@GE-qe*´<@Oo9nu.V$./R-w0w:3䋸J/J ϣs6\Z(57/ږ$MfW=~b_Sk;1rZF?m@H .@Z[IzQ;I FZKSu=Yx2NO%=+X,9.ԥ.Pq5P:ֵ4}˵fcEz$ l3smUFߴ'n Zirڀ!vcD]ŐR2,銲 XNl2%Lb|cƖxAbb2#$SS.Z%I4xIԩp#]tG-<•-0UV/;8pчjн|E%bo7.FW1c=A51jTcUwY9$TFЗmM*\&(f.@Eځ, ^UZNDOд Y] Qcxȅ'CD1X29'HJb{ԭ̇/Kc}CJ4U's/+beuŰL vJjt K3U3Dȥ۵Ӏ='|<[Ԡ(lKB=FV*qDgnlY{9{L?GږMfX٬Eшᐺ N|tܷarW٪V"ɥ0T=z3ƶR#3LEQN3@;-Ag//BD_e'crIeo/XK#[:#F*6}>DCjK71hh1?C0:<`۠ F~mwy>NU;w$ЯG7W}1YU [,@&-=ݮErg"$m;<{4Q#kMKL-P@] %iPtfZɸ3l@EFmk[挪}N}F%]Niٍܷz6*^#N\=iNJ-[T#oċXuBʝ/(:ʀĝ| PSة.2W/Zξƃ\;o@PfmMSGoook:C}崏t<ߌyEePQx<#C-^o6pNb\ː >?Q1"Уg|O191m"gٗڪQ]JK,v^޷FntU@l[WFe;~nvA-EUN7Nk\} Icnl)% ]"Zxh!l?V)gX"N" ?OM Y˓'U.{ri`K&SRBadݖ!%CfEQW J%{;RF Y50Ut"YދzF܎")-VXr%XLIw~*Xvfv!pcLi,<!LR^2ON6 x4 JB7T [9gVЪ+|bacZC w8/ɡtxjYqӦK0SjSbRޣʲv6{ι纞KC]bݹ%Qɪ'Laqq++[H1^Άd 3x3O6:kWV'y;8i[ѰQ@Oá 4!G"K:V$H{iQ1TܳwYSv,t%yOO^ vyVBN^ծlMOF~E.@;e%Τn{xޝ7m %w<5ւcyrV@Nƹebb GHh h|I4#@_YfZftxQpi1:Z/Pd5a(YP9KH=#,8,|2;[&6l@G˫H]f0zK֯]~RHiȀ"pKۮIWH4:ӗ\c,QYb]/t5_D IC`C_A]%1lK;6ճmKl59' 7gu)xfWUBiWA%}JmfYtbY ccf9Ck+B[ZLр&NM4MU &Mb&qƴFM|>Q|'E?_HQ4BPTTD}Ι3;::#˽s{2{̧?2^#k\D$+G S>^;16WHُ9xls _?ad/V ;RGї94juX[=Bڪj}\g)+A0_CC|x\x3NAg}ha/%I滏Ra-cjݮ|23=VOՆ[;?T.BRZ){G=}<ͬlew~S\긊dkhfpד坲>iģ29kx>a6Jm`Vt[9qulwpz cDR'QegB%k pPv 2A,+|V~AwY|O* zE {DNBq Sc@n00@8er]\C kQPzit׽\wɓ쳀~Xpɹ} VF]ex]E_$Jn҇~abv_A;~ihuUv[,OWFD[D 2%!AW|u 7m&Gz39g\Uӏx*m\f==px#DxOkt_&77%1!u3cYfx?spǮz^[j_/֙MҊJU;lFԪ cl_e6=xںycN/7Mиﮱ/xo@[]GtAY=3B@a|Mz pvߺ{.•nݳ2i^mxzǗ5M3.~{w/unV,YQ=FW]b48/X Llz_A?-ХFw H6/_{EiԚẘk6a'W} )!\%;R-\yZK"#rP=N8 詭4G9hx3{e{W[VKRZzef,1w!Irg<-GZ\|]b'h߲T45 $zۋ.K&2N"=gVa&j|8Gck{x:L t|AKqEƑyeXC8: r_}MJb|Uz/<7>rztYK?01S|I{Cr ?Kԟ='?qIcwy88`8=ή TaKS"'xDy&(|ϺRd!c[IHIgd!xS,6O_uS r;##Lѷ[Wͮ.?IT[:vQ>'{$-_6J8hDTHsa55i(?'H(Jr"iT^"\ n;VɁ&`rzC֝W6-@G&w+;]xtgT5W'LJ^=QD{NB;~y+ DzLZ])0Lj$TaZ=%DN7N:qd@fgqNy؞=KMn@ӗ)Ix8egïo:G] "5Uͬ}~n9[ VJywv@Ǜ&߿c Y (;Iۚw>1Vmx%P[kcH Yֺ_zA svCoMΑ <$SzǼ 6 1?zi#Ji(3XHPLпZnRm=^*ZR $D8[7TN#7U.խsEufA v"]_;w'yqY6B|,G(_=.EwIIWglv.qE͔duӅ.6u wn:k ̰4wipǧfT K<4)QQh]DQJ+8=Ev;]gQg2U\/6@'ĩ :iMqJP", }۔* 9,M4Нlw/ jHd"F :5=F+Mf[SH#vbVAPiSc!θ^Ҍ{wtL99;_ӬZmJΣ`ctff'Kwq暑]DYʃ)rof`Xi4vM,@ wpcHA(Nt)łR-,p(62ҜJ1LޱDJG**+ua?KA z05F>aq'`NT@$_ (5?Iӛ&tE݉t@m0wځl]"3ಬ; }M T˞ͤ''uvMoF}lAc.C(4@EHs: 86_exQ]T(gZ } Ͳh|$ݮՂ̈́77NcCkC ETSIVh\U3D,}([cɹ{ljS,~fDHRS6 XLfs\WY j BvAeBVUEYhr,bh7XF8(Due,& LJ]>=`@Ojvi; zj۞-*eT=.IV|YfrLq#nh*>BuΆ#D 4M#s?'V~?ِ)J),YEZq %uU4g i ,}i(@=iO3H00lz:YGMRe ;:(drdjb> UƹsEF~psXxԫi#<U&*yaGrxG2)<`9M]N XP9BEݼk\8ћú^KGt{ԍD4\$ށua)"Zߋ Lټ GԳ2†=Xq\37,.<M.?8h(qႫX,-cJt _*E.iF I? "!^qqJDw󞝞LMk{~眑g0}:p1)p&ΔWǥ#SP+9~\ke7ZNE0{Z(;m١7Ud~_%aˋ\k \ҿ3'@o~MA/DZif+ϼ,NhU4.뮚 g=} 7@G*(/ خ9P:m2# b醡hXM' w -MMNWYXtC F~)- Œ.؄=3ۺo}rzUyJYΩ[ S㋶{Pe1:,WƉ%\ VP ~RHGHO6l/(?=z'Ejw0#VeE)۔%Y9 Y] J3$d gԧ:Ȧ~`h|ZfOh9g=D& tXFe;IʇCuyjTc 5#/C3zfv:VcuB^QZ-ZaXl/2%dߤEUT.~kBfVdtJc@3i³evQ:==}+)dH&BPw 6WٽEow<;t}۶C˷B7+Rz?Mk~r1R æuˆL@ `?hmuE!cD[qeQWBiVI3/kt24Þ|./ lFJԨZcrݘCAt hҌ"VlQS'g/YDev[۲vzVX_\6+x'/W!鉠ޫR7]^qJ&gy]r&3'Gelx K8M9؞5m+n <8Ȇa|; MYr gdicJiWta0jXLNbc)L{kapUz"Mx+)IT&@ksёqZ^)&QS̞#{a,LZl?U48/<&(MƛYzҶ|I減m+} $pXؿKbgbakPnF/ө !YEo~njiodQK*%*I>5P= @aE\u4e QL&>f U,3 {fFd6FCs1z+t9&Ea1*tמŻZ;^Jn@*E[oܲD)~E/ =^Ӧfj:%[bu_R.fD.:M]F29rsp1RLdt:ޘ[=pj=$74O9RbJ&H%dw}\sOJyHT'?LWkq~ފvT#*H'}JdɢyR(VLtlTdv/hkH$ND9GR읩/!,W rK@(0 )Xuj~pÊèҘRRmdKuՀvo ʽ/|C#4( eIFYE)z&lp,|0]/;AY< &;S#*Z-3"WqA. q/ Ƨ2є-K6F[ܿsÖ&;l™iAk_yR ]Up&dX v )={Q$W*VwMx~xWzV2[p񶭍ނ-l4f&:p3#c<z^χիtX񲼸#_۪R3UF߳Q"/"5 l9lsrev="$&`%VXBS[˰fIP JD;UbC:dxsע6r0bct 4E0:t' ݆*<V\mZa|~T7l~n*ϔȬhQ{w>妱D'ӆБjQ{5M{ Y Q^U| 5ƹqt9եXW0͘ H!hltE]wmlai"Lqq`e&48H4Q St.$(ÿ?J=ݯGs׆iX_ })V%c6yJ]@#>܃WMW ַ3W69a@.Nma6%2L=‚uzLc0I T?5ߥ(v$?}ߕNbbQU"1M. sLEz zglOy\&to|K\: Rl qkx{&[/t\G/p 9uF‘ui:{s p"1s^`#9 JAޏxw.y Rd-Ei͓Gp4E Lg$OmT|pq'([&8n8w&E7UX]C]Tnwe6j[*pU "ʩo3n%l\5jGD.ײz{wi>#=l/ A:c3|X=IyY^%'3˒Jq')Caa6}xv=־Ž;}a@5pN혮M \I}l{Tɪ%+@UNT$$$kUA[ "/?EORAq7|x2tǛ+lt$O>r=bUޕ(A]^.;]Z$mmBfЋ~ge$=zxn*f;zX3Yi@F] D8n &̋$Xƫ`@7L6m ^.:4 G.'<#toei•m _xdd ^i}?;˙ vՓ:^+jr7E.h%ɩ ]յ>A;KqhyZ R r[<}rƉ@!k[eЫZ>ct^ ͓i7j_Q؛;0[Wv]$@[_ߔ:"ﺔ Wu\gJ@*fj~yluw+j$Β8PjD!ceНw} kA 2 R!#3?BUvX;O4[]TthR&=39btOW.`O( v7[stRS0,5"ܳ WG1E**\;;M.Jɭ &ga~le"?(l}o.wYH/I|r]@ru <`&be+LR'!]M`3M -=7]Y@WN ցSGT]Xw Q=d!ӆhΧш#?TTĂƏ~ܶjgHQ?I'yXZҝ6$,y #aa}ƾ1BR䵼I:I-Q7u+f\W~;yNU=>YN5S>q^}~aV=dpm1XhqS(kVףh: CU$z#ӑh:@37e۩F0BwnF0x*QG7dja^ G΍7|2.D{zaΦ* DZskd[eH?U@ou"n9?wKNi΀Ʉ8ԼVgw07x˥[Fl OuMZА\^Iz~T]ZdIƔRHwgͺmt݃c#V5 zuwcaJhV)c9qV[U +},B~-'.)˭t;6NR-6.*u$!WaM #~V_wI^QIsݭo{r4ɏ|oYYwS <wEUd &䴋 >, ]h٤ebm%yA`YglT Oo 0R!u͙vH C~IC5|1\RZCWt8mY#™{Kid^J|/7"3ϗ+m nXBNNm%Ϗ8{5tRڦcrd۔+ !YwVnc3Fr8JW@Ga59'I`#K βtz5UbUN(R39sPj #REP'29#,(7FȧO,gXnE-G|N6]Duz/^k'DO]ī籃&$]STƑQ$$kӗir܁՜ګ]]`-cErȈshAQD;7@w"^6HZ͜ 9pȼh3V?B ߔɠA_;U{iH/@\|qڳ6}-c9w!$#Yng ΤXoN&; sY0xh+&=*rNLfFJG; PbVC9dNЌ@ʂߑxXAzǡ%X*i=R!W05SFen1k.HqƸh|Տg^$;V%:P.d5J!5x1s',W 8fVrEѢ͠nUa:^SfRX* '¤e2蠺3B~ۢGC(R\)~ʼe NVgQ\v}ߑ'"|W/`cM>ktȋh唀MP{ O47Vـ2 mi @m|z?XhK@ٺb@^9M9H"{Q?-ne`,pi:M e͇+;_£xy0j[ZZ{di{~9:=G<\ZuR|6rLm]Z5+GY/pD❞Ó )ՓMɫ&Uds4Y)1c]/sl1-$<8.(M;f..Xr{>GcVnވuޛf+ncyϽ;U|U6Dg]E><'?O*IkgOD/¹RtO/bۡMvڋz=uټ7oTZLU>MswY/snC7q0LWY~-2"odM! Nt4i^X`@fv葯g3C1$ FʃCe$ 'rK򌛡}7So(`ϸRhY5bFI?LЏb BWςӊPUP*G5q/4^Km!/M/6].7h/{iD^hkRp sҊz@ @s=]ⷩu6A-+$l?KpvH9&]߻`pڜhW+:)3g $Gas8z ()SEλzV<-N>t3\4/Jo+U BsQ&]f!:[/2s \, 3% @^cnn1ٝzG+.3ox\(ŋ V36eWx2ɁwXc#3UCG3GG7U%W}@{΁{g3!f%iTuW9%I,<MԊpO֩߼=F"t^t12A|j-L`Wj,M,| gg/&2-2*n?ZzxA|2HݐQ4"lѬU=Ƥirm6kXv'؁L `%ܠf7Br@u5^֤CT`SzIDB؇9g{s(~P!C^:]w;;>0VeVv |w|<ض@),l-cg g9wl-s$f(/"7Fkk{P`ՉOS ~NTnjA+z(Uӯ9WW@.^FJ @١E־*9FlYi_9\=$0%6ئ5!V/k /fvl[B!,.oJ"CDPOk:-ЕQ l tDr랩hoyi?KBn.M-vgݹ_4I<]ضi~?$K@UXn6ڂk!O|IJ,E'J Qt}ؒR0?~{n>n+چ,1CR(Xfk8_68sk.[hXdw[_vh ˮ_v&$$}uԯGeKHӱLd?`oWbZlOwuJd;%'n=/f3CLMd9N~rw >6|z6I??įsk3#apdkyl>sm?!ÁD}L8}6-ೡH Obl~ qf{Uk?]g?-8Y\V9;Ǣ^Tffd̙!Jts :%wJݯ.QXG- \R1uàd)#:3֢!S^8zb*fg37*Jpبh췿򨉞D3ז/-h:$΄D`=x:8::n 3upCLC15b 7ۼBzc;wTևR ѭpx1=t'x[=Z#MUfNo%uIە?{= Gin.";_pI_\Dq[0=<%C VJ luZ*f/GGn̚. N7n^UtJ>|;8D$'n-x"mr] i7N'[^Jrp%Yx2rvx5.uxCL)a_-qNB T ⤰h'Hʤ/DRhr^(bg땑3t|/ ѳtloeHl%'UH"[LQhLCbn2BxʝU’|̩=n ߊ:">I3"]  ?W!7:ۑNO`o*%KvrHtzNL2HzE-@A/Q&$j9$</iNd:{c,O@{ HN$}q B>¹#/WMќ1ٚ"vN`!.'&FTÚ!wIO<1C=ZCɀ@q :^V.  n㜼 G%ѠyQ%OJݱpK,䎏#FJQQOo??;NCÉuǖ H':?%:6}0bbɚQ#J!Q0炮*Ws,"-mNޠu\ؘVjHM(j=Qy>RڏO,B18((f"#<3Y3O'΁5(^0 ;ј+Hz0{OSNjVЍi08U|奋s~|܇Exڢ_N\Zh%]8UpjfRwnP;MIPuc9iEoy&Ң;S?~/~wyY;ٖu#&3 F^i1Nj\il<:; ,nHM5mi,>;FyNt,M49CWUUJ:;!W8%2CxBw2~5njbRꕹ^H֋cV}\m(wL$DBJҤSoQMaK:!?A6! 4/mbޙF4+\FE1zts\~||KIw3D=N6[4/1+dr\5Q;DQM!){苓qKX[5 %OdW0Q{H (YuaK:NP-dx rnœkjNI|y?:Z>o,79U![w ռ^Rukׁt7ᾀ@r1+`Hb*0LM؇SsOe/ѫBYH l>Pgή@Rܹܭ,tlϩRα7r<@Tgy2u\Kd=Le#) Z-0=.$آ؉vF03*B-ުijeq/k5RT*oԸȝ0&A+|latb'(X2^j"? /x0 o؍5_H.+S|΁j53!k3t!,߭`7]cҲv!:-2Ջ;kW9}rϢLE6Ԛ":_["zഁ\9O(+o02rUtss /6ZL;*'Yd0YL΅9SK zpFab`ql3h^q.A^ jN@ˑ<Y(.ڔncaqbvq+I̵4..( 9QaYІX ߙh5<@ޔ}x3S :192>ˊ7O􁽖T{9Yɾ6WT#y|aα4EҤok$ο ׻fԽ\'xy$pwJ^¯Γ= WurxMguytvjcƫS4tcWz#>$Ę;BDOlrפ-_}T=7R'}s/0 zfmd0!C}b  #Q~ły#KzPuM ]d?, lRU NipޘJB伞YHF,}sRY;u6Af6(z;HԎ^k/ضu3m4,XTH<\bù$e46cRM=IQR'_]_;w>d\ Qi}pfd:n6__Q{3RN֤*$;zҠz}Lܗ{S.7uC~uxK/7:3Bns`{v-I+Αɩw lXU ~R7M~rW^Uf[JjU@ s(PYuzSmk{i# ݵ֮l>'171I0 A$H |UT A⃚De  (ҊP Bg̙o&L2jm-wLR6j\ /'uolށo:phgݕ5!$/P7_&7J- y;8ESK[d|v;82"~p\e_Ki2G_\SלsàTX],qY'r38!>82nüy^[b|3|uF gy=R 1}[uQb;<_~=]#qm{{wWS㟵ӯ 7ZN6UֻJE ami<Ǩ=5xc =ma)$|kC8_.~b= @skN^]~|q39><86gɺWޯU5J2ji,q ɍʘK5 /߇S-<nUB6%G܏trLl|C>88?цj}bnhZY? W)VC$ +\F ۈ KrBI,.`^8Ḅʨ788 bq lFdߥYjN;N[ݫÆxAX7,ǶV жm|_^/Eh'9hUZ/om.57EQ잒zi4NHݎTl17iHK [RĊ\uh#ds0ejyh!$Q<)³GY%(Rм-hέЁݕヸKWCf9['RiEDS>]Xo6P]0*]()s^q)L܍$ \E7a^BF R=.Y g Zv`MޤA7W64G>cb+8i"9{Ҡg\ai{e:㡤i = LY9{h?ppÚ0 zyF!+[Jy-lϒK C#͑! ~HV^ЕA(k^TrB+pJpR%JN2L cb 0kף?28,-iBAQ;1r:xZ3}.fsfjpƝNMi~%\4nLY"T? Y ?DcO Fo\+\)-r?E^L";ʡ\؄C~{38}&#c$Hdu&6jX\wu1bٜtg5t 8BLݘR#- 7<H>3,<}nn$3UոP0mo""Y'#Nxd ewI΃Ქ}L_\dd RP-zw>ww}ZĈYbסŔN-,Up-t'd!&. bcQ~{ 'k(dx7#-fi.CS ]}x}̼7OM\rǖwtpJCF -t|FFIZff[%y}1ǚem'ݚwjiYlͅ],H?%nQ]L<|( -[zi3XaN Ø $_~ &*A(Εƭ60ȾZAqb7W j1^g87}1& C 'PYQӵ)d|53jq b֋ 6SD<%;(ߧ Sߕ,.fо9K!aGZ)m!71p3KgP[E;j^9) /Yc::Q◔.h+L9,Iҙ4+J<{ >3YK5`qْMBnqvyCଜ<O֙D}F'<4Z>K=X9(p*޻&gO-G4xqtG,=E٫Ii M+5X*2QeG%^U=7ǚgfS lNMHˢ/m3uȎIpV(,CA7FG^>\ ݰ -:+ps9Jt2rV`qCAz^R|imT.,x-xZM; kI.*w:|r_SDIaɬSqDwN`n}PdĦ% %$!łFLLb4w]ʖ(jr @o&Ԁ|, 5gF):q[ؤ#RKFz@zR#Mp ?jhyaQ@ @YBy+ibHz]s.ЂQrG^8$C)8㰼sNY-ANFGajrL9Qs:PzS{vtGS1-AR"'%!lpiׅ)S-: LFꄬ(lOD9x K$(?\ +Iɍ)ZٱJ)~]-7BFTy⌓7KSd7 \.fPMi h54EnclK8ch bgsچ:)cW]ȶY ;$$l<v8b`ƂI(7rj&#eC#Za$sHM-QR32=ۂ=_OܑRi}Hj`|Kkԧ]ݔ8p9\Ƿ~Gl{iv"Dy{ݰGܐo% Jrt!Kg=tA}5%?p=,c '݃Sއ;tC)Up}#ס;L8*/9 m.`sA/ YKsE/#M;>p]Do?O6IENDB`pydantic-pydantic-ba0aa01/docs/logos/nvidia_logo.png000066400000000000000000000145321517143232300226660ustar00rootroot00000000000000PNG  IHDRRR #PLTEvsicpnk`emwᐜFއgIz| ~šP%A`訤U棦[垟M̃z鬹~З=5ߋ!m8w q݃e*s/zwjx뵚GC~3u!^▒<-'Wt NXʫIDATxzI 0"ԥҵq~B_C6 woU$Zԗ0$:q)Igυuf08꣔TD MxR1;!NIEf0%I\읱'm̞24\mR\&tc4'R#G>iR)^/>{LO|UwH72+I;ӅD >i( ި( !̨`GUݣ t5I|G+61X/Q^6nZޯUk&3b!%j1 #륑KB9ϙЗBJl^7fh1?ʤdJСp(*B*hAn:@9yKUcBJ̪2H<i0 ͍nCn_"q{x$ygi)+1Nm AEJ ~'[T4n{-M ŁDxDkocO}E^YYvs62)~>HFbS*x2|=|][dO9TX R%. _IKCJZ0)$ϔeFIF2/뺟DgۂߐJ\7uaĊX)cSN!UHnʋ>C < e1U(qkSD$'BGz>r8g+Ds52G <~@ΡIBDytW1k]c\X;ҲvP`ΨC/'E3i kk*y,"PZFiĄ֓P¼wI]Vh~eRDSDAi+Қ Fe4^=^܊a癨eKO~K2vbWTW9,~q]F}{8`,x y`5aUbNNaK;=*)3h-GLΤ@xFD_qהM.ƕ覵c}dwAF%SZD1REGucw: (H^Rbr.`N"Z]|6&63FBJ$qŴ5ǐ&|5*4~B`1TٲP]qJ -97L.2$G A0^zr."4)^Xůw#lQm e4%Gh{7Hǎ}vYþZ}HepLAx 2[ ؤ1eރ4B9QG0Jgxuk\Nsf/94 %Gkr~H36yOmQ[Ri;m>R 2*tt&d#UAq Lni,Sv*-!}}`ώ4XIjoL e 6!@ɝHJRqtlM}oLSzw_c#U|6\{,%G"? pFPɢ:Ru3sQ]P[~ˈTqs\ @yyύ4ֱGz崎_-&qH/y!0zp z z#MVϟ=+S:fwAA.آD] w Ozx H~OJT7,ډc"Wn =!Ulx4XQ/=>ưXJGR…ś"Rx~ꋪrkF=Z$aƌ LzDS, P3`t*_즘sGd69#? B˨H֥c;{Qyy,eQe{Li׏jP(g=B# lhcO&CIfF(觙(#Sqw)'H7'{i=?E5 idiBzhQ>$Զ+ׇ~/5/bMx.GBZ{Q.R4hTi5Ӷ%ήt)hONcy${;ҕb 5>,mLTr,@7 OKI_+oKog-G*<*RQ@^_痏}E ~Ҍth$$zq'J<,NIn~s%G{Q%)0w}JH[zu;Tf' G"GLibHx00?7瞼- YHaL[cSqe_Uk@{Hy]00[l>Q׾z}]l&NJ,"8ݍw癲J~Hɫl6^.aFqHMy`k|G{wmiPNN qJU,(TEVݵ]VrFGsoarrfB*G aDRGe'QyP URqJwh2T}pN{+}E9-ReN{XLTh)-RJ T>/pHiPnnu*WxH@"_?|iRRJJ|H))}RR!CJIˇF(@.Jԓ%W9?BcV,NHW-8(q' ` {gyW"uOJwwtcӚ1{ _/.?71* y§$0=顱6dD2)61-obt?Zn|;HE (*Ytx3V3`+<6.Vb7s XY $!n1(N]>lR|ܕq6JrM@qdP9㔚A+=4G.ܦti[l),a9˦K)96{ ւȠzDnKT[[ ĥy6J1YG=Z)KB+MelJGvP{T p\0EtrAUDC JQiL?1ƇCtJ L׾R~(?ߜ`S*U"ҕgjQ:iEHTjn8f7R'DO-O!n83xGe&Drj72v|gbT2 NY)Z|9w07B(Ur+0(][ݚyv1|[ Uw@lRi7-eQ\z{~ =&q}_RGl ;R=_JWAaN٣9Q;R*엽Ud[J#J咪d(P{rRV_99 ]RF>w{PȧIq'Jlʣw+,QA]x(b)PmqaL]J>ah@-+ivOp(|vV M]5^=J\ T~ $'DJSnE']LwNmւ^[oPSiBqɠ=e=l- R-Rp:m3x: UYtS2&x=*t _h9Hem&ĭwJ9uқ=Xj= 6y*0g^TJEi%|Sx fL0JWvHlY}!9q+LK4t:6h*yC=C[)\.ۻty(漵D6JEyd-cV2Q8WyRp"SmaYRSEc=##NE=6[8oD#v]Y~ug^jGm g^JYH'R8a͐`6#؋]ʃ,pl{mU?#xbVOU97Fk::z>;"Cg4oFC BA؀pȶ ,"E0ʋdZYaq>H_)E"uawD%2lM&b U ^#"~XL3bB2.88-عup/  MνиtS ` φX DA D̞Ho}k&ҳx%.;BiIdEm^#_hlsl"$̍(0 |W7/@E}XHŀ;0( H!K$q٢ `:\} =0np,`C`gW\`CKivBJ~V'0sCߴ.X@z $9=K͚f,."e7~`#@к3bƽll0XH =O5d]`m @n}/*{o$`#[+:` sL}x %6W#Pmv3,RP̾"# Py?\$ G] 5%4 bNTp [aRqXUܸB*`OdγQeV.`a 7R"X1c0Ѹ#4ZgǭJ=PVHg_x\=J7Y_Cـ5*౲[2Pѯq2@HΥSjɴaU8T<oaīX/MTjF\ gFG΋6f;FFMm6cPSԿ.G`%PBB^o왶̅k] =W9+' 3_=s7j6:{ŵmLPc`q=ψv#kAʫq(V\k@sKcDkcd$[i8>8tm00(l0q#x^ %Z??*UgxLb/">)sB=zѣ)8F.~}r041C 0kl c^Su&%̤k@eS0#ndXS9FqT쁣c`. f"8>tfa KVOV7E[l K c/,Tc,|qQ DbP_Τ.n|:,dl(3j(+1.*3D؜++jw6P@X/j%O` 0) M8-oߕ:(v;3$˒XOP؈#L@ackwF׼|g(d#t$F0\3@:v`G8DE`\J]}sm@X{Qez@[8̮5@}-wj}l׀%Sm`$l4ob}pV*WuU- GVcItLY wZ !x=;@} /ce` @Ts`[`wK` puk{,5Py@r`ܜkpx 0mbM@`8Ot0]`Ѕ*4{"v^ys1v 9{8J`dn#2 $+Ѓ9F[N ,9M4cic+ `|;QJ" ?/c "ϥG @_c>qO̜ 0$_ǜ`E=,#r#NLoW`Ih@%KS \xYa6P `LΥ. 6]!``)6v)̍6U?H@:ЁѣG=zѣG= ~v!IENDB`pydantic-pydantic-ba0aa01/docs/logos/oracle_logo.png000066400000000000000000000020461517143232300226560ustar00rootroot00000000000000PNG  IHDRζFPLTEVW6tRNS@fIDATxK Ep%\.X;phG}h1ʈ3E!B!B!B!B!B!B!`z%JAL@Ε})A+A0 lx aBrAث@ۥ J ^]0TQ rghP *]D0J ,p`G Vݘ\ QlUgw.H.S$%]++<Y>zzX˪PDO&Jʨ ƀ> J0k6tҽԂQI{6Cwoh x%IR EׂxfL&h*ὦ">\Awt[ w8@;[zJ%ȷ?Z04g#R#J,WF!.# F!؞ tOACARp-XJ+>7/%3F`jB¡ ,`Rp s]ucE R+K,t'.-Jv&()k cy7BЋþA@j8eJ}2 ^miaGjCBlrm~Zd E9 |s6~e{s63 HoNgx"'`$LQ벘ǫ+OE+# X¾6dY=)-M =\ X Xt ҂ Ʋ߃MtW8@RP!8XщUxeeEVfY1/O֩1B3&,eCQƱ35(.qltJ0 |NAq( uUWz3J诲 qy&l, ! ➮4у e?;MZ9mM5xt!B!B!B!B!B!B!BȇppWzIENDB`pydantic-pydantic-ba0aa01/docs/logos/palantir_logo.png000066400000000000000000000225101517143232300232210ustar00rootroot00000000000000PNG  IHDRæ$PLTE0tRNS 4H[n§:Zz93a`DoU+ FEMՙ^c$y#" <fw/5,2*!&(-gd06 CA)K8 ?JONTRPmG@%h= ]VXrbeL;>tQ.uq_lYɠsvSp}x1jI7{'ik~\|WBCp IDATx흉cT6!(!1H&LHLBXA("pMK*RhR ZV*mn.5dI9~y?@!ssω [lպimŴ1>>0;u==挶iݪehtt:sb&!ص]:wہJjܻ9&@pTWؾᦾ.iq~ <ӟ#u= ̡YRNɿsr:%vCTCTKrzg8qh[8\[gdQ .Vp ?#D.c?(B;D/"59G?ϙ$r()@ MD;y$t0;ɺ妙[D.E'y.]ɦLuǣOC{eCסA3~ٌb~H,g6bvbt>M&IC'3< @{gZE'ph\y.=w5C 3۩hJ`txXvҒ,^N\vrL̷pט9N)`9 eו]GK}e> !<&bщRǍ7lFq3}InNjnA{,n ś )6X( b9hշӢME-+9wE9Vk#]< 8נӁனhߥ=T0d5yL".$}*v7:XAge Yу%2lzo,pEܯ@x<( m&GA=h l$n6= ac ?<RYǽ+nK$q:/Ȣ}衳}r,pAgG=oSx3l~9_r|e\m|?.2^VY#xn1kk-i?]&Γ*~<~Wۥ#CPm:SjX :] .nrLܧ~tѣ;|%?vv㼬oڡʏMZ L%q_T5f5⑟(xoē:?Oy9ce6sY"Pyq..٭g֥F9l=ϙms$x%hyOu(JhÆ8]Y}4\kň iN0F.UvN좼X'[4έW_Do{kN\ ԜSE:4/RΤMD ޙh_RM:颏1}T6:l屲*4敟՝UcV>I~n,C'w2,f$ZYP<XfUʾz[u ]Enݘ_hi";f ]íْ7(:&[m<[ <5E+sf߂TbWѺ{кr_Y`Z*'ZH8OE U}S[,SP`hUXƒhUfh߀tJן`(3݃:,g7mP9T-hM~*=VkK><4ۇwВB%GN @K 2%KيV,| Z5ռկy.j!f]v.Zȇz^;:R Mp7D sM-X?r~Nrx-) 8OҞ@}#B;"k-PS5(wu>VAFc6}&LZ /]{4x M[>oI}0!%vR9|2.F'oYpqc8d Z R{@b[02PQ":m&d6>?4mX@q\h'Rlg׈K\.;&U@`l*9)@M$li%~-D5mE O*^`O5';J+OB29|d|wua;[k:NqOiߢORvj+-,'u;k9x~2N9򎷕Q³GKʡL`, W =)2``@C_+\&5;6A߱77văN}G/a>7m?YPE>v_m q^"x(򯩁<#WyGjn2 X]; m TH԰cT'_%5h@> $l򓰑h0%+w}P?@.T/_M^:6~3["[b>oa  4:tIP;+jy51d`@&휡=dd `'D?-h1bd/@!کqD΄,g,E " .]xDshច[սG*9j(hhhтۈ:nI7DDK_`ݖq&/]Z%j [mD<}Ckӂu@l {!|-h%ҏ(#u0ˊ`#kTLMj j9P#|>p0ޠBc heB|4KcBjimL\}[cjtgRVd+UA7I47Z:XkO-@  07PKV2/j 2jT\r-Tj\ݮ1ɤH ug#m H@-I$[1BRhOPc_8Jc"6Z*e:ǜMt.hЊ4Fz H]C'-he2VB2Ac楫Vd*k ,bjW/hD[-i>16PIiF[-Gi1ʹP V;5sZ nP硭 F"CPu5O\1Tme+heB<\g}![X$SkRF&ky_k?l 1k vZfK5Oi v -XgZ|<=[k{mD<5Xh%Ҟ!QQhC-rگ@hЂ5ƠG SFIE{/nydMzQޚ%"9{ K>xs:b_ o4CobYhå4ۏo6pihW-#l6\\-quBXNh-`'yh_B[. s[#F<m,'yo4]9DcWbh%AaCy2tI!1 f cKx> @c6mCK&7;H8/R:tp#D+A.Fw)!,sljhq$԰w:5_JuVLq߄^ā;1/j vP}LNld6h%$0|ȩw؆(| KLPe'܅6_a_ %gSbjb;Xב?::gևF0*#~rjpF99>!~6kCa$ïcL ΄S\Q ǵO:D g26$FWO2SPɡ&aZ>Z,pliO|u<1a@m3Z.d˘qYUNEC )@ 18"&Fx -&Bt A yD%NG QLze KBQGh%SœzGBp%Co` &GPǂ yZICbR`['1٤{Od|EPˢh)ꨢ΄=Ab0<)۞x>$x΃邖 f|KBRp׷Ǧoj*žm%ШZS%We -ﲙ{QtȐWH.1.<\gh1A=Oe;[519A_s\ǁ~Qјh5M0F.6ʹn$l@ipv4IPN69ӓuYK6Z>VK< Fy{V,W !?S6@ v[`X_p7׍5hA!oXL}N=OE+ .'^ނ0C+ 3 -)<jyLDcE]M@K w0P-)Tv1+7@K25XdtlGnlZ9}?>8t>oK,"2ڮE qEؠ$6d5[)]Ve\~ c%͏l9Ik,p̐nDYhYӒct#$>jC#1A krW_E 3b~ ZXSLN= =^?1<b(5nw }1iW#lp )sq, $B"G $ܤy`f(_̔5䤼~+UQ-FZ \tnPUٙWK$[)v+h}QQTy(+;&2jF Ģ'uoZ2ln})qp `L|ērYsעs˒fKk\恝Df}B[ fs5'ӡ(76>a ixDTRz5K,*>H|ReGA_@.Pxda듥蟎gB>m2n|1˵Ygwe ̿尾FۭMت`]b\#['OVI;tksNWUT(az A q{TpS#AgF'h%rƿDb9F輧f~ed$=Dbgt>sQVe7d:F5,%3K8 F>|: PzFAXGt7eq`5fۺ}v#}öO[ѮK"z :O42tJtnoy ~k6ݖH+={cc`1rnF!o RˑK2[1s#Γ*.F&T`99wЮZ'7pP9ZR1\Y x gVF-Ug}.AʞΗ?RԴF*}/ 42w&=[G2.fUmAFnG, /vo^~bso=,2m}a|+Zᅹ)se?w|Mݧ.e+Ė27z,q.˽raF>'sw'ICiS%^W |䡆+KKx۾Բ1<}WC;\{V/(ؿr4FlטN yʶlqCvƀ4݂ٓ[C$1ř'0hk :3jך2iRt́KD|xr1?nr7k2jE;e v3}Ym]ravppʾQM 5Iz>&nW>3t!aI:~ӛ z2jf:nR6БIKrӯѷF! .Vnrk"$W=*AoB~r&-y}f7?6>P𽓯`Z+Ni Sm7m;௥~60*pTsO8L:SХ"Gukp$7wx\L=G\5y>h>-q)PtY84+Bb9]')GMBX[0p ܟf\f D〘kȨ3QrN_fHm|) DM4?Ⱥ/8+ 2k['OrEبq@5! T܊n_/-ErExq@5uD.k [ ^Ru_p$WbٗoQ+BX Tch[HL,|F(R*RgAq*@Xm& "lm8I]ǩk/8_ߙ*H# NȬ-AWFjF82*B +꺯l:."D}!aӊЩB~SVa| h?-HuE( /|:%ƒ[O%aЩ8=)łGvxVE}*{F{eWrDm SExEڋv*"t>]HaYȪЩP "s @ăO ЩD"Զ!dJJ#s>ܚ]>N'S'wDU|A?J*B+B*Ἓ4SV}tZ:uL"L,C@'̊pprVtE}vcЩ_SE6a3A4Y:u_D"taaFzZo`SE*!Exs"tȥ)Q@?,>=7IENDB`pydantic-pydantic-ba0aa01/docs/logos/qualcomm_logo.png000066400000000000000000000162241517143232300232320ustar00rootroot00000000000000PNG  IHDR/PLTE2S2S3S2S/P2S2S2S1R0M2S2S3P2S2R2S4T0Q2S1T5U2V2T-S2T2T2S1S1S2S2S1S2T3T2S1R1S2R3T/W2R2T3Q3T3S3T2S2S1S2S3R2R1R2R2S2T2R3P1S2R2S3R1R0S4R,Z2R1S3V2S1S3T1S1S2S1S3S2T2T2S2S1S1T2R2Q3W0S2S3Q4S5T2T4W1S4S7\2S*F3S4]2Q2P.R3Q5W1S2N6[4V6[.K$<7N+[&>31Q5T4W1O-K,X.J+X4S%_";5O3U4Q6X:^6P8](C)D3N9^(>9R'\,Y0L&?,\'C":)BAR/(B'[3T e0$/S0U/V6O6P-K,I-W6N+Y6Z4O7[%_%?4O6[4[c=T8N6^&;#:5Y3O/U7]5X5N4S.L)C:a2V2W2Q-K+Z'\-Z8]tRNStϦ i 7 RŒo&C)@+b[Ny/ͽ*e.^GfgGjS=H99{}8˚k(؊=2YTYk=dun %Y&h:yjJģU1뺐$HNã& H>ҋ7axt;ʤ@' V]Tq#YxtZRrԶUb)"ԞΣ[7R5i_ Z/+URG*MeԠXdrݪ>^ԥT - (rHPc pts.<5˽(+O!sSzFT$F `5r݊`%EC2G"3+e@)?OB(N6TBCu݂! .#[r܇qr݂R>n![j>"#=y lFOSmdYR +&7$.\'CWի~\'UʜcZf(;8kSGRi ) s=*o$٫XJ w.I4*MSFJ[:-8f֞a$ڻZ|=AȆ&YШol?ԞB̿WebJ4^,iC5  \ D*GFz VF"~^=yO񇅳`d\tOwЖ"">O'SE}HF!{QlEDVm*{HZVC}h֣OkwP& TD4hLQxtT &3}9E&r?yEU2Pvd[ohduHs?LrS}Pj<_coA*Il(0H Kآ`Db,WZŠYY2ҙ̤Q2k ~e}ADU=1N"*a*jdl+0_"c;>xK&J%!P dDj5mGLDz:tL#?J m2Nfj>OL8#,^ћC:ÂR$ d7jR Q!Xy2EPN?3A1q+E+35POhKFֿ,Bmi^')&Oc  ,`> ?}$hwKIFIw GPOЪUSNOW4ѕ%=*\GT{>=.=rUW >)ݻh"DIKM z 'HSHWSL*׷D/JlFrVlkC?rt?|"F=C^Ăfzz~tC5-x Io-eI=탖'w=Ť} #z%`=%VD G^ a|b՟0tx%&,ա$ n ᯕDjnyb9dE0$JGƣ*ɤ >/6Vӌ`KF[HZj5igHu;q#"c}K\ h/zA d$o[u|aE7;(*("5t)D@cшшFcK[{{o{m~Q% `Q}\nn]̥5h5t,=؏V`vI(0u/7Gt uLwt') #׵*hy`t +Xs\!d!7&Ou@t$!Bz< UzFzC߾Tr+;;eAMz=ަ]oN FNu9.ddGx\ZZ=:iCz-!i}2Kf22Fәڍ] ɒhAzFo/]Z 0#4X{+A& jg?rNj@sf|ԢA_* 0hTX6y0o`l5SXފ_ 17RB*ʥ/jLga3$ϋпSnv=K @C6c~B~ǡ!l<w`A  Z rOX]Y D/2 |;dF"ld1ބLO`g8]1(j缈içjk zUTr o  kq C ;Z~xYctv}ZJ  rs6f)æ4QyYc}*sڛ4D2 b+0JO[; >9k e(jGN W[$F_T68{XI_mš;5ޖ끠{v6)A~:4m'!76]!+YY-XOAE=򎄮X]CO wo$GB͑QlF H>r̡lwz+re[oȮE7{È=컶E{4$Vg/=>f\4 2 72 }z N{3rj<9"  kN?k{)g^,_&YWu 38: Kk[zpCMvNCoFRl">ӭᵶZ {yI( q c)e6@*/4Ad~ $Qd"2l$v ɽ ۇ Fidj6 P`kZL2ƪXSrEwp!$ %ԇ6$tgSn8]8 N*[-=;lM뢑z#P!~R܅:]-o UH${w<=LMȩ"ƌ\a谐RfBL*2y`.uְ3/"s:ɔ+̙gJɔ;Av"3[Z(! >ީ $!  :vZNCߛ,z} 1ied:,]c3@b 5 {w rg?~lIܝH5y@Ѵw.YN6T>dKTb Vvq:d{S* 7 F DۦUB:!Z?F<6Ѕab-Ptq_ =&|R{Ϻn=;|NCJ!x+Td*J>H6K@믾hM `Ӽ@|@ߍ D8^rܗ$w:@fgAPFH8ld|@LȄ3@&N_ԍ#J DQ@ᤷYvAh0"ߩxu,|!7"Ɉ-ix>eY s2qP(smxMw]q[%`v<~S/(ڞ`(lkk@Tq?ln3xZH,h袣wф}'UAdNN5ojT*FMK'' @v&T J,*?'Ah+EC9J}aw)Aw]>H|Q- tI(0f/{b 0[4Z<,ZPbVv7v"dHBߪ[!  .䴹Kܫ pe??ώ0#}NE `q-%X) ]y 4tQ6ST`jsVG!Cӓ*MmY] -@bBoF}ǩ䔬|hG Z?pCx2|Bj´[hiZXjL/X&+\st#&ڣ #5}[0*LBDUVb D:Xl ]ɓԦ#shn:mf50KTq \ f0f~4t8$E<%25t?]g!INЗX2?̙`oe4^i9CU,TUr= s:pň] w4VN\?:yG7r8ؚr:1 y. |ݽ({qaԽp?Xd5N_w^f ~ %.Kqdudu R7kIJʜ"-P)Ē~Ur98?+%Gokfȍj|S)0pe1- Py*xҥ yu h&u]|\1;=,@AvNȥ^:/y\Ĵ1߻PcrEbEfmJ ?b'",euIش= J"/uU7`xSO5hR4\HQZ6ޏ^I{>XR4QmV[:q%T'TxC.g?yBri;ťuHB]Ɔve^? 乭N3+̺lfoy*pIDATxf^vҊ01"oK K\#1qakhĤ>_V9p r{#D2]`NBi7~HߓP]0 bUJ0 imJ(Oh"vGG$R''T8z|FI LC޼Z2aO"lx ofjqwD3P#zDm1aE{H4I{3*`c6`c7% }ʈXJ9Vyod%ݚ'HY>!Sz h,g1؀=m2okXMya^~KvTV(;qGFwEP 1k9{g㔄6Pf$gKF SA62V˥\vn a$>b}g =bz)3Z|`{@S0 $y 1 #$1pޮvd7ɉL\L fhR孋{r֢"a&aT 0~ R eN@N;V*iܫ/):PC*kru()J/eydcWv%U$ 1 .gw7vcwwwwc#v va"bb̞b`{Sw_6Gm\۝9r)OdH"Z{/"!`(-{"d{0Xe, D.)=!G"%Yt֕ĮlpBFI?K)WP|Q,'|}7;t%ݾE= 8 o ,K 0w/ Xr:xVvpfǿڲG8gQgʡ? ')TO/X}A 0YM ̆Bat` GgA5sm\P~MA `*bs3[ȑ$UQ8( J"8R`2;`< I>&ʘ_ :pf䳌 g̳嚄6$J讒q]x{fȷ="%W5 G'0⓾fnۉ#Nu:c c1jŪgt ŧU&U:4_Z?tʪr1w>I2Ū~(C=ݢZZ|~V&%nGb7F{̞]=L[@F:P-x;*m]F77 ym;( ~oߗ bL&ozt܆Dh51X E9{yVh/h2ݏ]" zhb6$|`v"z$f Vuc.cN(8fw⁊JDH IBBTnHL@-En<8-*g~og&! BpK]C`vwfgw~(^餎׸3} EHvȲ=Y?!zNg. Q^fj9Ϛ#r5B7i+Ժ> A`%F]iCs6 iYK.aZxH\_{J[+D-?6^aHKN9HTcg2LB'Fx}.i~!ߞ#H5.L@r/=1&MrK7C#Q?\{e;ԗDh ;2tqk,Qrxblk9Sw@a<F!ҨϽD}h'NGXqk'ЁS"6vJ5Sy"{r.`1z TK</X(=`,F'MYDC[#Y䁞 b2ʮH }DX(&WY,^B0/myj }DLsg8!c!scL EJ!"EN6񳨘^X>C0uwpcD]#@!BȳUd#78j9CUVp#5Վ.\z\ȵs4t 䨿*"p_-x"0EJ=2įcڑ:;ԉ7 |>9sFס ~:ߏc:tKw ji8yW<^YzmgjyT(@ l!O690rjĆ-SGi<}ZQ 2Q(iN0s ԺJڇ +Ş ]S6z9Vw?E҇u3erdfOQ^P{lbJ*u'z{4C΂yR$AT/44L :cDUh\b-zIb !装[y @nTY.\X'!z 䦮̔S!zSsLGũW3vabT$bgJmY'0Un4uܢ[\LQaj<,f~T=W!Fۚ/j2s\#!X0\B9ٔbw>?NJ59'ͱ้ȩc_8#ubOV!xrM.Lؗ"-u(פDgqqL ^S-2W!^ SESĞI7r|N,ě除p8Sc-D&SLWLP{nLݖ%4*ğuMݖ hfao߯qg1/FrA3 3)kwP&yV$g KEI2vR@K8rJ04EIP,W7:̵C!iMfkPG̻w5\9<̯" a*dfVMknޖ<LM: xI*.(MO3}AZo1u?>0W s}\;$/DfZ;f;ɃT;L }K0*%/n2ޝ`bהO}-]#S%q73jV8)(<&y{ֺ} Ao]R$9m|Ebn &I+u$I+g,K&xGތH䉀OR7zr 3{mru4B9]WfjfϛOJ蕿8E?$ B%o/Y$/"$ǢtYR-rMZWˆ^?ˢtsDr̜[iCf/)|۠=YJZor8yY #KuZ7fvC0ƍ,j =h/IʘdCópk]w<Ae/I䜕ʾU[ZZc^ ,$j0{cX.)A✙-XFS鎒ft󮓅/dx0۹xd_EH.O3'4o_T^V8b颽?:Eʊ4̘=Pa\b2R)rp;{Yw|eNfNΔ9;6ϚQGdѾUXlT|:?u[ 1w3/#lQ~MkX)ue{~,jM`q e ]J|aqϊl]eX=%Dn`ZNjcL7YP>Y'Z:2Zn^44+u ioݷtL[}/pLk׀Ehx7^;"0L_k5tt_5{N& [C^7mTQdb,ue7*3 |uGzYD!m6Z[X!LX>&1;$܇ՈlcTWȎX1:{2 LtOu\Nj"ڟ$o+l$_0~M$Xv_T^%T19C *E|rF4^Hȕ ywJq;wamo{f7m}p>.M*p\^ֆއ%wtmt7l"7sN\tH+ܴYSvZZТ"Sl-;v-t)f9t:]"z.r~wi~Ks\im'{7_l7|]Bf2Vgg޷Zo w|ף#gN? 7rr=Yb}kmm7^-GCe`!6>(IENDB`pydantic-pydantic-ba0aa01/docs/logos/revolut_logo.png000066400000000000000000000101661517143232300231130ustar00rootroot00000000000000PNG  IHDRæ$PLTE___kkk:::777qqq---!!!˛lll 󧧧III???eeetttyyyPPP444ZZZEEEխiii111TTT)))MMM$$$888YSIDATx`@TUUUUUUUUUUUUUUUUUUUUUUUUUUUUUص P)-熃U :muݜA]"gfy>:Z>11z{Ǵ{T$L~cImY}&oꪀy@u?89U!TmNw\j+ykNC(n=U54 )ӤvDj!gR < H= _ uh>iGd03݇ &)OP2!ƤM ( @aQd$C: pI:) N,R:h V@骸rTR2YZҞ0@K71ӭnie{M;WܡE"r0w;gvj HKa{/'܁VzS q+5`LF&K!ŜCLKigZH͌p@x@z琥SgXBv,< GBIv,$YRst(g3d[9'P(!uK?Ыka}?DmxCԐTcAm_ҏ^BN۪f&2\/0O2Nz~dx%H@*.[CiQ0pjY^3O*W #HtV&VMC8~u**7~a c4Nѷ^UzJ.n!mY15_tyYUGP3 ^pCckWl7['$ӎ kϬ!Fʓ̛x̺=Q"Bdz7d"/[)u6 o_D%.H,l9 nj|2^̓0ͽc}eh;k!hRD5quNn˯+Ԭ\>j+ဈfCWZW<~=8-ts:E7`'$ƎJV%ެ"רE`ͪ(A"sBڬgiu,a5Ux)7A/=-n?Ea=Ig(NF#fxO($M> {0q$Y9& ]sJ2*e`(ēE-O|&?eMaҤބ_[GɥjhEƍ [$owM\ @%`(] 6G$\*V/7~ق HT Ԓcd\*o{PKp]_{,17طACEgpdRZO5E$Rzio#RqǡLw<NBՑdH;IxwRDDӒE&Iˏbzp+EQ,͜ jbh{dR 뤠mCv"ʺxbHҟE#rn~D5^<ןT.?1x/TXbz Y|k]3WU1ZTz1 $U' / w6(Hwy@O2LdUMsMm$b;KҨ`;?Rdc."v8CQ [~g))Uk&Be@9Uڟp3U `[u@؍ @f([#d @\tM=µaFHTw'pK IQM sgPo9wIx/*.C5MDH]|@Y%>̅zL!ȃT@dwG4ItZ/QX0-`,xT@3s$*ǝ+ >-؈|'cH4l@dD~ 1>/ Z?@繵`PDwmcQGW݄jm,3:ڰ[ϐu % UBƨr}ݛbGs NW _#LuYQ8?ԌOwjiRwBՑ\˸F& &.8誛ӝ. >e-HF/˻+cBȺV/,۠;Y%t/<@ѷ gl3Ь댿2>*J7*  I%@E*,џaT $|_G?z9fvxDN 5eQTո>5$o7GNֈKACymaПHޠg =C( KϲEC? ;`kX@ Y%\D+4@Ϧ $`ߠG x-@=dBMH!#m z[Y]RVQd|Bm6h*fD=Ȓp@_P, nܶj+#O2.jǓ#TbzR6$϶!S ;oe` "0p|jAu@UM(( gJwPaT|JOQ!x)@-,黿Дũal *@vPv]kE*"Hbu&[Q̏cQ)aۜPmEb Š^eOxI'zεzEp4xZ{x4#h[W`pwS,\vFr6 V |o9c]SvosX86l&߮aaaaaaaaaaaaaaaaaaaaaa7{p ^a ,=e IENDB`pydantic-pydantic-ba0aa01/docs/logos/robusta_logo.png000066400000000000000000000035501517143232300230710ustar00rootroot00000000000000PNG  IHDRkXT?PLTEGpL/ /Kף//////KףKפLפLפ.Lפ/LפKפ/Lפ2tRNS X1{%沚lCafPIDATx閬* A): D>{~u[d?x n,>gt'mo3;?sܠ?,CWD{9G"pt+Hrv?D q'P'n& Qp4Io+Q [C`p) ЮoS ksi54H)(H>>{ tXs 4X;R#.PFg:TE8D uH-*[l6z@'$\*@LJ@ΝhQ)2pU*ڒfG/d&!g"[XB8naT*"zݽEK(i69-}*@ #@}1.PHKmdJ+9/3GO p A1S|Y$:__3? Tq3+Dٽy0S`PutSO*h$27Hz9 y^1Ͻ^t"9! ! -MhK P%!@$!^ǃ2AFu8$3IpLx %AUEn'47W spoàH*{!).h>m/I--sƼdViK!zvkK7gWSicgE+DX].BtI7"G{txQ4/j3Rr'1$_ؕO{?q_{=4ghn_r<A 6Q(+ vf;y@"Ax ьNɢ? n]xMnι[ck(l^,h7;;;3^}2pnxd:܀n ɀq?b|ʿ|=QNQq^,RIENDB`pydantic-pydantic-ba0aa01/docs/logos/salesforce_logo.png000066400000000000000000000155501517143232300235430ustar00rootroot00000000000000PNG  IHDRæ$8PLTE lfQa:vT3!)@]D.}q$YHL%w.tRNSe K3Dw'V.=q ͣ^R黔k9sIDATxfNt( Dqy3NgQEٔ{wzEDDDDDDDDDDDDDDDDDDD2a44C[,#?ʹ',o/U\1xIJMe^5Y(FK&}W0S,6 tPotzF?6ʱqx:Ey$z"f髱ГRTW^N7k Sɛ)4G?o13,L;>*c%lVTQw26/&nz4< rQ)oBrB hbhWLuB).|@whZ^JxxsY^U$J)9QW(:9r(%h[ f[i8.Hьl Zk(Yc)[m)*89@~`%TCʗ&SjEurΨ|a'Y>δS8r-?QM93,"l_J@"]ւr<u;| h X_z=Zd;/2:z0]ȧ5SM GE,?c+E^mԵ@13 44c&ݒf)tV54g$3k銿݉r@ 1M罊V$.$A{bB5TBC:/T.5TfBE(àgh0.tzTq=.gn; BǶ*x~WU7eu't smarp, nr;g{R͌D?ݶlZp]cC6ۤ"YԐNnT?3K ,5ÇVϕL.HmKyKsW27Y!WPCn:;Urrqȃ t5&}[jkxUR(e3:Ix'!۸[\@dKS!;xxc\T~ay +Xۼ -ʜiX᪘/ `ǽԄ 8:a1*/_@ _)d5d*#^k BhrN}TRQRjq "d)*6/u;n*L1#3UD/,@VL)T}~sS@wKKQc;c/c=$K轩(MGYdGA`48l;l/DK7xߺ-xw\:[qY~v#8p. . >l;CSOWGw!g'D "8pΟ x؞ ޜ< ?{\N^HOt~^`׊.Aaneh{> ]GѨ*(x`_H((߽wo.>O {O_{&ޥs<|E?,S*u𿳾\>Z:d*ޗ>]\+}gt_%ص}`h8~я<=\s?Qspvm#ɱs@Q8 lmx @" Gy;av9s8zn .nHx I`mDv'qYppu61>QCB8ꟺe_Eevʑb-C~BCGط(3(CDsF;g8߬_6_Y Xb[K7dD;5NKi?h <8Gm4Ru`IQoI`*谛`w9PQ̸ů&[JL\.¦l3 )7({EMD)1Rv*%Yȶ9" ľ",P24e\z 8 8"#V(r6UA3?[Gs D>z&H%2R4%Sh&wX9)T'hA 8Do30j"' S9 @ILfi(.m0rBp3p|4)"{(rM ȡ1$ T䛛 ΫE~CA2q\pypulh/--P8E\Uhzy&y Zn\t;ΈSԩf\(ҿ!HG*ۜ(vhPNeNH_jvGPu_m>ߢ1&6Є0$9AJå)9 .sOCp8R5Z}e71ɠ [h)_bf3, *Q]ޅKY 2A!zEh.楎 2HWJH/MfjF$_ft+888A"%11ԋ-O,?Y@Ӷ.I#^޵[);RqXA;tZue^} ld[(PM'(c'qyjRdH-uÛj*}"M~ ;6r`o<LGtykg:)pgD*b8YLov ;h1fH 6 @XPG?@ςcoN>ӶpHY k񅽕Os_ -I^@`EȰfc0׹dlx\Xfr'_Eb Ma3$" ,P8@$c6|:|'DM(45fdWwg:jUv>Q΢η) <Ws%k9*q-4[ 1f6âJRMe=7+*JK _<l4cgtNUPDJ CW9Vb*,C{Oܐkb WvUm e5VѝG#X"Qd#Y.ZU/`c _(xn- Vn| FHLH붔qS|IYloLԷEؙ'%h/ o?'xEFB gh+ad( P`2 2=|ŶjЬR/b>8G{9q'J-`e\մMR $O1lVOP@b4R^;R _3*$ ,A*!=TMp:lm0b,Qs,&{|sX`pƩnETH{_ڒ6 o 7<sQ]JrJ=̰~Wl.$5Cm;$@ Ib8ku=r~Ԓ-B? Dy´[GPrNSlħ`W4>1Ѓ /KxB&y jI1`kٓ]$A9ut$Tׄkr}3R@ٺ ,uTד6ֿ@&i{ha 3\h E:ݾGk7QeXvLX~?r9Z!4[&XZʻBHMN*mF3Z`;bLURO8iH(rh4EZ0Q _J:wC U4Kr)ܹ5h^`)x:(;q]~ yZv\>0ů'3ls:5]~{PvZ!@Nt;vA*=FbJ5NLwsyvwܳ*NԊY&xyOW6a7'+PGhAuvOOK[W"?Q7 Tv>9wGr,:}M±bA.IX5jOd(S[ڂPT ;%#$Qxj)lѩӓ/sD~O2.Ü^W() e8̮S*D~3 ,ǖ,uĹH~@Rdue3lIpZ>o-_G3nX waW'.c٠q|4@x/Q8f^7V'0`8{q")GuW<]iV80l1~ӅTt:6.*oBGiWA6DcEW&`_H h  ,#`UNxw%q;^X d tkPkMk.x>`_'Ђ#p[pc/9Q FEPc$}mVek&`fXV4\ .`w+pT; R{jg9\)"00с<{WH{+<%q?x~[lI*W$:;zN7J)* T_LVv D}w?T! ;oݱ"o{uy'4 ؐ6a)w' gXݒ LcN+?P-bJ DP'Db.\\s}B$(ky w*k.|8k3С,w8jr 6VRgZ=,NBK)oiK򮠁JqPЂK4/R9N6Rzq|ҢtoIuBR埞*jKzSS% j)?MVR5ߺl|)˂Ϳ 汔h~*wg0p!w3m邘*~JB 7jʭZ3?Tn஻ FKJЏ@. ~65anވXh݄9)Xg tca )uf}g;IENDB`pydantic-pydantic-ba0aa01/docs/logos/starbucks_logo.png000066400000000000000000000776121517143232300234250ustar00rootroot00000000000000PNG  IHDR/PLTEƶŸrxUK} uP}ZxU}\g8n%d9qsMzV8qK}fɻ%d`*f6pI~R$kCN a7sN xSyV˽ضVa»ͮǤͿfK^2pՁ>w;u~\'i²ȹŵ!d|YƷ۔óE{}o7p'dʅ`\nHrj,mP@z tOT-huQΐ>m2lwR/b%~\KEZ qK!`6tņ{XrLkPʼyu\iDqa+^iA"{WtuPfbOz kDónɻ8iق{vXӁǸxSnH܎~KvDu5ep{T|y? HvKZPtRNS 'ڴ\N>縚|6ё`&ám!M.ʁm\&Ak`=H輪U҅r_׎L4{*}{IDATxɋA!IN<1 xW'T%JO9+ n " ^'ћ n' &Ro]&qWL rْ$c懌;2Nf2=͍+VK˕IR&QJ3(O #"Ogחg([Y#\~} PJr6]+v=2%H祝bTzn2ϐKD 8]/[HXTs'⫸^ 3(h̯B(@iɐuu 1.&A#TkӉr;ݏ2"ɮ`2ic6r\6 m_L!ۦC=UIsE@Tk3rMPĀA6E6#G>6T`k`7-&oH0D_ž0 D%B|ajm E>5Zp WZa\>fRAW4GC{g|. @54C3>5![;;gkSh0WN( ~)Qbkm 3=1A!&{kr%LCy}њqa<> P׾)!>a4wm{o1bsJ>\l`NvxKO[1rl{'o&d6ᄌ_]fyOVOz^t'nb.!bٖE+-=p4&Ó6_qЍ.&j~~XK4Y~!It D 7 g ̨Ϧ5*` ܈IM0Ɨݚ+`Ln:ڍ&Zrg`$:ٰY/W-WX5ӃL?zC"zߥ w?ŒĠ2Yu+.:M qT{H$6W/;b=(}G1DࢪaQU*$;lB|u!NzN;1j}$^411wgZ)*"JQzP-(FшG=PDҀg`-j#Z+3;)7mv޼~}sET,vu2IuL@6OLIiYD˴1&In*Ųܜc9䜚NUxd W PljQkݞvbN|"Wb4`H_豘r 'Re UI%)1ަ=G[%kMCX6) Q%DYMєdwMLS97aG1%blc4I*/}?̠|pE8b]d:߲zW l4l<@Ys,q5iZG.u>yصig@Xc e52!Px|7,@ĕ68Cϱ @-? UfkjޖpĻY8g*)jͫ_2;R0v JQp`Vu>uvM"6j p" 8uriU!-O363a*[DŹ*>+)p}zQx:)g64')҈4*&.; !7 }4n{&6kah$%i|quSR2/N7ߜu_3 bcZ'{J"UKJKR ĩf{~ pl 8#r+AiT&W~j7py%x]`;^KR~4:ШH(lU?8 i^NM9fB۱,ȾXuZD]hDL"<6Dzt2Esy,dU?dK &m@@M]"ARV6dk DEXLOoa,M dwb%o7Js BT46Ce3'g rk:G_D8$JCv,>}̓=7|\QQ)"`q "Q \,?uoM[M/`*DI<KDX\c$u)׈IbVf$sYٌh DI"_/R,Ia3#c\ 0,q&bnE2Yh#1}]#N[lvooOƒQsΈzJ~\7 X4 ih$)}9 #T^~*f!sD' 1>򭺈f1,QMܙJ *JdZU-*hx]ݺI|Ou6+]U3Ȗ%#{SIh˭5M'LǒS'x-;`>%,gvp) jշ>n*^TV|q|oy_ZS`[Z O82!8W`H/Ͳl^73EV_ng8*<ݾ%i0'{ę$!wm!y-4aC[}aw8Ȋ¹SL;w7C ?{& %eS5Mʘ3^)t t8u_5D\j/G,y)4՗c(QRVʂ 4gjg͘^.*NJSEKK 3?rwo@AxPXCQ~_4>V c}dzeV,s뒆{u5̿gn.{|FʂLYaÑkIe`+ rZhW@5^n>4NâklyhOp5Yڄ''8$ͼ~l͎-@A]L[& )k]?>8feTRʛlqPun2hvtyF2l gp,(mYs!RʅOQ[Y*òǬCuǷ khw nYT#w-%\=eʢg/n2EWa`ׅ%59_:֣ (1xET RD])l9v1*;6àI)q}D<7d1$bTǨ5eRB냓:k%ps\ǂ&¨eWӡ=a#d9>DFTr{)աPzGWsl.2~͔KѾ-)q^!?HSb%->-6xqLYă}l,A5VdlmVcDcWgpl>pX!/ix ǽdK%̎4cտa&>d [귯bDc}1YՏ5 Qr(^x(I s EØsC:ء_8z%vSd&J4qIhCh2)냵X#B̝>&)* ,X.Ȱs-Ӕ%HH'AD`/L1^#Y$TH'OP0lXhr<!k&ޛ!-T$NK|0My>d o_J9o+m+K?i#V꫱359.bD铪Ŷj7ƞa>~|f/ aI}ۈ6jX%?G}q£'#jRq B<}RNsO:`1@EV F>z巂ƸVAR*$WFð zkB߮EGecMX.N?q+F{۶bbVEو++N_bX44y'wmyTW[\#nElx!ɵScֶ&γUݣk͛8 bJΝTy<7}Ml1˸6@4ٳ :re˾;1;e &V|KB?cTvx 8)o3%vt*EZqiMo+?S| (,ҧzh _<^4I,=0+vFK`"~N/SFfYc  ξ@R$Tcz׺ "c G"?O19q>'RT7IO~bݧ^J~\CZnм+ xrqD2AAW9§8T E@~R"PL /+OESYº7 ;-HSW-{`N}(jPI; ]oC#; 5ϻ8./lǕ͡ DS~]礸Sc\ *z(>fǘU22ѵۯ>qO7XԷ^~yM_rhZ"*T;)J$p0k*([8L)wg'2 EޱKdׯh>|"4#Gm9jbo&Fh@$f ɇ'{ yI [8 Qj܄+t~\֘vZor- @m>:ߧjf":Od͙]P 9Ӡ!1\=!fo,)aߋМ# ޯ/:}SOW"PF&9Cuey FeY#k7y?o_qzǢo;)_oݏ(ɖFnZG\U"mѣ0a{={OMȏ(QeHb %s :\]ZvQ. wA UGD{죷.Yށe [yM"p&Ǚ}t.2I5=WW_T-2z)9V3IDŽwb߻Zʼ*'\](1~8aEH88}~0rd0I7ȃ̞~_S8dNMxڈN şm+BH 896O[(Al)sɆakbQZ -U.,@(zzfg, G(پt?hvpwe |h! ܃c .w AʌOm p!Jw,Pz%#E¹ ^Tl#@R59wpoܳI_\|y'̴B[=K3[E=mUFa`L_Un )4b @} .1oܩ.Vx*NrDqHNu.Ÿ7vif3^CPl$e{XнF*ndo5r$snr3lFr/鮓(?@4 ZA ؛C@oNl#ǰgno"ՍÉW-M ĉZ:T,9lR'4(60Su­CpvOaޑT]۵Uw}.ŀZ>A'kLA"=ڹ|NI2.Y!_0$}mi>qq0G:|"` F#IC(a=N_ǀiF*'A/ևB*J=ݕ2!Z7[Ru&t,vacX\6X? 0^A{bt?fP8)1>% ^z;ob9ͺ&ۈadKMY {t(9o/ycQTwHqW;6KDž8)tO;6b :4ӓ[1nxsIS |qD0'Ѿ}%< ^%w7fo NςNA2c RMނ~XY2{3x9}~Ŝ D`|nM1X9(N׳eîjW!mݭ¯:Wo}Bhn@Ss,F]+b&Of\ze#tNp#T/JBo7L^{7Ys>6j[ӳwqoُ(fՉi„8pB2rLH\AO(Wyw낧r>Q&ߦ 0CG7XBOsmN TXZCϴ*aڔ hYfߖhAeP<;FH}g %~5$4EHn8*?uWO˃i {00q \(!T ]ha3H.pz0dBRߟúE2Y $'RY<-:}k]F}2HSBrxTah"s6syΑMĪk"aW'čm;[]|I s*k2Bw7pRP%_݇pd mvI'5+$ C|ƚbz-H6lF˹.P@uH̵>hI]Lu>ZmX/$@_!~}ߊ)YR͉0nWB84!(]*&bCEC$˦-oAUF!3 rS)u~,С|*T!8nqPg2U ~q`/v`ۣt޴yOjGH*3lbum)h"=a]&;E[`Q%Rnxz~|7:vU1g0&f1Oq0ދ%}fnGLnS!W}lWQ iQե2$]\c@&Gjy)!y8frUOGO UԳR)[;[|ۏm ":YJJj ꚨ"Q<&8UD$q1`Akf)ҞTvlv| TI侣/낒)j^5T$Э/&2R*}{2+#<RThYMƌG/f=aՔPM YYrŖj}'\ZݭN|6pG`mEZ D֙tX%j4)`nn( "U4KX*B6LaǙw(ATT/o9We~k겚#HHl ,VT,Uh*V>W DD}0YEUzf$.k,S(ͳ<`w(!6\RA㝯;P9=y\d5 ȧD&ACYim-/TiTƗ5L8qXwWbA:@A!UOSx%BB&R&fgAՔ)pO($]F wJsBG"8k+%*x QأWF<\V) V]aZIp")_s2J} +8n-)?Zdy&(A(wj Ulr([7v7~T7 z"KG~0F:=W7*Dh75PIR52"KR_RXc +^c gjWL,찒w,? tߗ4磾Ź;n7 :o2{;6aYɡ,9(|0&lbBxN/|&x~]_0IG.9'=*P jWOX!~18اpE`82^*S>2y FWi,dܬm>۳R66!z%}[Q0 - &isN:RXZ!# %IT0Z.6=|ϫ2BfNoK ֨X'[Ge1epd7j]jLFeET:WWd L)jタM<$W%KFcK>1?VҾoG !ޢm)-=,[]TѶA#|jh$\z/ܵ"8M!k wZqf!A=dنb1^+rcO+]t]7]?sOo?ӛ8Cj&/LfBQ-+]ؒK] ׈NW>'NMw$^]SJ66.bD{4u = H3Љ6#2ytc! v Ni(' BD'3W|IN^ M5C_-ρtTwG5b<+,<4TO2:t!q+~fK.pp(0b'fJs܈qFng(|96)ػp |hm? @b(Z̳r|p5A1»l 8tѮHR {ZEqūJ>󖌪C7a2qKZS[J*.(:&J#hK c!JVМ^.9_x9E'N8#ot>&1K:I7+vl}U|s^kB+mF@IqDk(&*Q7I~H"Ȟ+WblȆdtĔ] :^UlFTaug=EOI74=!jn:f:TNVd~﩯P%;sH\ IEӛACZ]gOa8 N;n#qdqci )@<{Jt}`*ѝLA@ˏbZvhmt(qiܣ#ҷu2ܭ.REc2d^D]Pi>OEtQS2BRzs=5] t;VsxS&)$>]EWɹk26_vݣ4r(>jvlE20P8V*ejw6rwLXyg\yY/b9n{98pvHWlsiqw?>Z ºwV4$($0|կS@p㸜8p>g))Úo7،7,4$/5 W@ Jx:bѻ9:2ٜ]~o/6شyH0Eͭ~, "˖& `8sf%0A\~x^j$W V.VRQb2feS 3m  Є|q?+Y"_?M^#DOѳ.dIKZ2"\Fh{"r NejE(j*0΅yb<ҤȸӔaGL1U^6jz.-ψ'm󽥬h˜D "#D܇!Ñ=ɠhrZn/4Gқ6ۊ5+8 RKy /Q';nVV2˿eCNkw(3@x7~4Iz~Hf[X9;sf 9!M&tL۔hٲ9f nǮ ۊTǞKL>#ii hbq*y=҉7X/.1v  ǧ9LC&whٮn`6ql DId;1?u'M ʥ)sf$w-n[sktu<c+{!\r?+[,]O_X10QEdwVܴЕJ]Q4r2lt ~|zI%Y=hse-z2Pv&Uu!j-lV)kbtcƾ42Gf_4ORt=}mj rAꈍ=gk.9 ^V:cPEPP/nOFV_\r&ߔh5KBY'$; =|a56=Ruқg~Oo 5q5H [g \Gt<5^S!ˌR38~̓!8qRr]2IuCU=UcwoNfUU!@RYx}Bs?m-x,S}g?R*pl.MRXNfosӊ~]OZ(Ұ9iF4TH>߀6OTh^LGwٕ㪧U'8US {LVT`\#$Æ_F(Htu@#oe * T_:}, ;`jxÄo(ױ~q*$:4;AU,O6 7gu+/jbs S]s_ApU4xON: ?Ǒ  UaFg@?E>_Q{t*9n%Y M% ٥-E_ޢ{\S|/ܽY%K0W;_N<Jq~epA e[-9بؖ`녀{]S\2ABRpYg"_I"GtZ#i%R~@i9CQy=fp™\z^Ir`l P|8/:/~ZO{vR{0"P2ͩ0q=Tbkh$u"<)[XVGhG]SƲ3S x/Es ['}sa͹^N#G;G,ij|UtnпנowjcK3Q,.-4%/pl ޮ47l Sa#G9`A݂JU8 Ao۪=-'c!(e=Ŋ=>f^i)g v?`%*F^i Sc}GWu<6h%AUB0mxbBt!"v-h Sl]^gH0Pm"ATgQZ5}vAc:ڮeq:eVr^ %JX: 5e9}qM7#KocaȹoO?7!en7R%, ԡN pml"pjzYA TׂoOwLRm ~e.&nIimq ktW>,߉Zt *wGUL/`c 'v) 1t..j2=ÌFf*fC-gwoDF֪̓.&ʕ`Lnr,S^ЍP!hcehid쭸0kUHukj miaYLimW>eh4&!9$$@^A7̐f9EK M6ڎYWTPtJs0i˘v*kɨ.:*Hy+528NnBYM2ڐ=7hpt- @Z>jطEǔFW&>UϙN{>, O{4V_YU3'9@Źň f:ͫE^dCrqe=B4n/KjR"Ak8{gunc0՝ĭJʕi3ޡ;x;cxNvTÒ9Z̫=hdϽ"E2sm3U-^_!٧ }8wϠC~@)xw:riKb*xlu KP+q^\4r_܄;\h=|ތngDZ*7ai |t>c+QHjҬ7U͟z e#SA 4YVW57bD/ǔ`:B8O8՗@5Wv&HW~ka~ =/U'⵬@kUW[_pևAрyU;I'K&Y`ά|/:gshpܙ[wpVqeв?3Nh:!(/whVa|5Oa e&z "r1l@l]]'wq 4 T,4ס,從WlGHAwSoE)%XL }wdmbjj/o;s@޲trz^{92#ōdɗp(D,W`Zq񖬝Ks<+F=u|?AWsb_noXB,_NkgDHtV#(4;RlG,(X͡Byp_naqJD''V{S}Ls7M43.>l%˜*IwAױW߸OH8\gEP$!BeR=^żةzH}8ܫ` T|{v9LO㗵1 Lb+m 8Kg0 x/EnQN<EEjfłg3E2Րs.j .6ۀ< WV!yX$}-3Ɩ6|{@CPd營C½D~鲊P=w>"d\5+({Oy8^o,u 7GXږ6`|\m\[-kH75 2*#W}Ť q vuٿ"ᮔ!X(00-QD{Q:/C!Z?ђ)Ml鱾ҲH8S4OTKJ(jɓI~'E\}8qFcw+,L!4EnOq3.qoj,( `,Zo 0 <=|[iO "5%XqiTWW\^iQup{V<6j"ܽ!Fc kt7aYc7ҰU"tYHFzlf!+F)r:ҀÑ 4XXq0U"OYp+kDWݸTlP}LvfΙJDB}@>/"/s&@͟ʔk4^?lɑ {Jjz},fT.Yɽ[e>.6 Ykd%JvJz'pҭfwIBC{wtg?.%'iR߽!*q)/k.U'³?Kx*!B5mmT9. ז_lfV|qbUVpF 򪊥t-Ij"+C{ 5)Ut_V7^SǶo{nRW%'Jb݌.GT]>MKۚXK퐭J\8z~Hry~(ig_"ɺnX(?|#CJ>T /OuU \E<.%8ѺeY}KMd0(Y}=M)X7cL$29L7 5!´/YxL쨲繹d(DI[9iՒrYܜ{݋ cxˣ oϏY9,18Bx͎/O3%:B]D(\_#u}ͣrl=[ܗGwkU-TQ4# xATG92D\~_ rXDG&Gvf1\EŕFj,Kۅ(5oEyV,P;ZY6|9b b*, >bkc1 *|P$ Kmx}X49*~O27> 3$+F&B/8M]ckhSRrAY$6Xs} U!N8009oRhGYmGTz>‹=6"?62Z *.hҪ)[ &f dBp~!,PѠ 9r bc {(xŜPUgf<9!NjVt+=*)VFΨ5ʪR"MXb0CWJK)x<Ʀ֎^G% a ZC8!N=塄rdA[tϤKJ}ίh_ !o-goW)1 '3fi3u8>(U9 AC=<Qp`kF*mrfʐ=)pn(i^4l[^ŧ$CS5=Ȃ>](ː'BڐҾ$|%VP+7_a눬d^CLQi8O5I|FVb<\Jчkt'\7MJko)D^0{%O!KeχU|`^IO,c?}!W2o}bR#cl#td*%7JB6)jqG;ېx5mH/MKKz=%Œ)|K>DHmU)a $CE/}}2 lۦtbRΣDK; -zpt{c*KaZ|kd |y4:1F )KF}O C=8}+1(}t8I$!G0. վy%+&$!V]7ˠ=Yiw>6;^sϊw P%/%}'R5S]`"1 Y=kɖh`pHn. m~el ׬Rc$)[zQ|WޝЎ3{:,#iTCVzL@7p<.*F;@}uWR.ϔVgÞ]HUy%xEWL)hIaU! r&8qf;S+BұdD.g2}Nu~p(+RsqWk*="O]354Q؋ `= =E} >[~jroQ~rJӅdfdR7y-]%7sLB~H6ԓH!Y?fBcK/'F"9n/!a^Uze*غA5 9.BrĆl7'_ Ix÷!z[U6ʢ"I)]H(^H_ W*S𬷸֙K^Վ܍D +ݫf:n{Wx-zR»zVެ*pp$غh1/4\z%YE%8{x{Zq1"dD"[2z%ߠE!X3:pR`gW^<]A9]d-%OVaq.Fn<^?a}_ԃjG ua?.{ጧO{Cu-|TSrCj@3[XZ6-D*5PF00ّLfz: +ԇn(/QE>)9& PMdUTq Ʃ Nt X|fk':>؇ `Qy`^LJ6 "6\(bmX'b%C3Tz3F:~/xEhG$nVӒ3>m'fh؃9Oӗwf.uFWvx,|[C}¬#CleY-C)p7j5G25p*tt6EAt_Ν7ߧx%sOڀuPG9M޵E3YKNpd؈S,g\$cʫpS|"TTxT _TlFq3 G_roͱQ|wa S@'β\%*3WVkX8ɃAo7섌ҟuPgmv!,WֲOhO: Ƌr"Z!SIi .pQ\Gs`Pna%~ε~x6VuS*yÖ8@X#)KkC@\,F0 쓍-jwIM%M2F"=ѶH[>o;>SdlR&o#zysRɎMjӡ*7Ωe̹=;U6)-!~m6ҁ/y ^o04^T7jԄ+EuVuL> LIrO>Q11؈F\寀 =5F9 TKl7ʗk"Jl&jbg/" '}1\iK< L Kj$_) R嘃a4ˋ gfݞxM~A쭈VkY=`? 2HG7wQXlxaSmuv`V|J{n;2lNtPf:GyuB9x݅5r[2'問X v!y+уui!)%&ݰ$|I :ȁ5*D|a2ϴ=zog<϶;VQ +$xNѹ؍ T&ʜkE3[Ń_ZZH8nm'K#Gغ2BlT+7Tkm.cycOq˻ёb`@92ta-p@KgIo)*J[A \jgL`#o/K:YG jeD]2me|Y2+q k~fV}m6m-?+n979"8sw7q3ZiLQR^ڡA@#tK}2ty<pF"svqsZ ̃;D$EqP7a-S:7!FMtu1OVnџbHyen-unc? erluɵ:! 1cEf4+k83a&4bK28r;ׇkgcdC3R /bPep,冰-}|7\>Z$L-1A[+_ 2AzL =pXKu3pIKc2 ip;;֘ckkX gG x : 1 ]ϯ: h٦u2:*K!OC2 *Wމ\ȗS#ЖZGM0{ r_  "wi˨懵`XE ASlpɇKTtCMcE]{TS-:WI84D&yK*_i$ΧA; L* ]A5VRJ^,v[UևY`/ې(Qk$H)M,~M iỏQOۆmvhdxN1j?5@= ȈDƵiD?CnHF~=EfmKh zL9'Q5oB5|f0ϼ4l0CUDn~C?#S]ÀG_5P`_z1$}N9.UV#,%El@o{̳)3GcN8/;o?܆O~_%sf6ĖL,,[(ʉί蓹W$Db._mձgK~MS_G8<Hr,eoM보74ת}$qSעR+,M&8p5,{@߬-tR.>gLvT׼Z}eW8 9]~ϰe\2^EI’ALddސ$z#LP=;K*HMi`m$Eњ_{~}Y (o$Mn)*ȴzbRy81]C"Du%+f 0} 'f[gsH ``ҩwh˰1KI#ְ%JQu)9%4; F62hJq0uc 8BB8cx7Sn&)~MZ4LZPɂ}m1ݿOn{1 : ܦ7lњyϛx&1k9-Gh`اbRz[wd.ɐ+i,gW;>SLe 7wVrcl xMӁ4z/xPLN02;Qr~p ?M &NZl2bqU}brӔ$hȗ/('|R$( nY*WҠ9JD,uU/µE0.K], +&ӡYL'L"]+D@*tp;6|zUI$" YH63!ؐqF]\] WyYDMa e$.':=ZX b^sSm#Ҟ[D3/B1/Wbu/ RPAXΤ Fi:`D:XDx=Tk"@فT ;4ϣ3+]w1':nLybU܏|݈ԗ.tR6v5/җ{wf~EEn*o@ȩn?.?4{u#њ {Yo7D'u1!Z^%*?է2DjPB֕|56 ;ڐA㩌yUtEJ:'ʎ$SCZ#hH2Ą#"\ˇ7,1&YGNn1C3W] S]Q|hzidI餢aEH2[vQ68=PgIs=h'W` b\ثHgZ7VjN[Cp@@tC,` r=P6y|i?NXaoΈԐq:_ʃ,Q+R;NPdR7s8:r]漰ez|(k?AE<M{K+\գ6N[wBsMpa#wAP>$&'2):. 5ϟq.}Z:4SL1y6K \: 4|1Q~%M\^xcmi?o1;4)=gڼ0#T5S"7"sjN+5P?il$cXǑ`Fo:09ͺUD8UmP&JKƗ, |2ђ꒣ֵJ{zX6{]zR׏%ΰ|hUr +€Yu;jAH T/KĹPnvlH`M׃:̲ͮX@ RJtػhlыR~,o=Lg/t:01aA39ipzl ]դLX\\AEw[<@`RK*Y8I;cvض,WsRtE9%]|5B0[m,c ~ W3Dl5b t]ČgWPnf.ytgd~@Q &z\rV7r"L=g]8ziY\ȯU*|S/"ƾ(f^7Z?;f$m~G14P"jϭw;y1Z2t,bU׉ \ ُ !z :]u)os?/ ab/?`.CPE2CR|~׍M:Q!t :Ev!yEM~_^y}׮+ѯJOwq_X%Nva2BIgF2sR@f$9b(nTղn?qz b*."-!7nlx6{Ħ4N%jw. #仏i,OHwpU7אKͱT#EJm{<*\,/`&ʶ%J* %BK"P[!@b|K.Zljdiy2B-^2.L}.0_IENDB`pydantic-pydantic-ba0aa01/docs/logos/ti_logo.png000066400000000000000000000122571517143232300220320ustar00rootroot00000000000000PNG  IHDR/PLTE~l6tRNSmbwQGeX] .!*=L8rD2&}Tަyi@ IDATxQN"Qa(P&:0:8 &\@wtý[A'yQ/S?Ϊwk8pV]? :貈.肈.肈.肈.肈.肈.肈.肈.肈.(菃7C;n?C/#V[{у28]` )=ct7@cJ;utwϧtt7unC;NGq;3w.tܔq::vM[:n/B:z`SO7b:w+3< ':q:{&;NGqm$~~NƬ:NGqM\DG &:NG'y긣Mwqw 7у`k&:zHg:>:f_:9Pw] ]^+?gߪA V.Й x(ew]C#JG&C`IN F׎<1XFtѝPm>4unyW[ V]ayi)/| >tUܣvܻWxւ;r,{?V0yM6LC^&f)tK) sqX:Aڞ:nyP/W3yb-2T`|j o __͎[Q0cq,>~bu\t֒xvя(qGEr/CEzrq?toq^Tǭ~"facut=otI/\7srŔMǭ.ɋ_-%@a.vƦ㌣ʒIn 6g\XWd:̣C[#YW0: *+}el G՝t܈O9WxiW<:|Ldqv܆Dʝq;>P `[!a=-pM^Is-tt8rkqWCǣ,|BnT~8mkiqCh 3f*iCqrUT]hͨ/や%Y<.PG' Ɗ#ゅ+$..k򸋡[.iEe$ψ>lڒqL\5x]'sYqb]qB7|v=:]ָG }vU,8jx2,u(o}vRCƬoG}"d ࡛nnWɉ6]ؖw"B<[ )ֹ$dxFUDBX\ApCʸ@4(:SPa^vHhK q${qd5f"=Ϋon367)_YopM>B0H =3\xNe&%t91%hp*[fd9lW8Yi7PwO; : &;tCI JUtcB'~|1|Ri!y=xo.ЎøUt\N1yS0fq7 m|zyS\ה(? TK5uW׾)XwJ#O9!1@wbk@B);q /"KiBqBǕ24 b:3\xFau/#&,k&1Raٗٸ:=Ɲnl J\Qoj$Ufalj0:{>Ӈbxe mwmg%n?ٻ KTh CGłZ?ZǙR Mv2ۻgT(ma'81B-B^Ba9}+YL VҀ }!19DhA ,T]BH\.3A9&C5e>}!Z,a̠_CC+AP(OQhɗT }ZPHЧ!ZkZ=;=} q)e&wP$eSN[9Tf=-Bx+˩cFr|^8<*r'lHHg㪎WbUїYIENDB`pydantic-pydantic-ba0aa01/docs/logos/twilio_logo.png000066400000000000000000000107201517143232300227160ustar00rootroot00000000000000PNG  IHDR/PLTE1G/F1G1G2H2H0F1G2H1F1G1G2H2H1G1F1F1G1G1G0F1G1F0E0F2H1G0G2H1F1G0E2H1G2H1G1G0E2G1G1G2G1G1G1F1H1F1F2H1F1G1G0F1G2H3H@e7tRNS/mh4 ܀U芢e<)#v` |ZBϭGqLQ7VIDATx`v⭅`0ICIkFli._xs,tCH5LǁUyyoǷǻ9-gɪn?o'@SZE;~嘧 ڰ;Ygw@WQT,A [/vdi gc[`A јozD+,^Lxć_ MW1!N@| U)7rۻХUCzcOFZZ,9)STZ!~OBBZxsأ=+܂Wp[N}i3!F$es[:z6`ZP`2%u؍E{$џY $Vu[mPџ`Ra El>7qf{V,|XtgsƗCA_ BGO>zUWȮqo'= ZĿ!T&:z`ةZnWmme7SJ*[ g˵I_WmCUw%ϗ8:۞x/(uJt"&Tx(Av^au,5Xz|Cn soxtA@GOқƏ~_zثR<-*ό"Y4>:J |Eh.Л2S?֥c^3woh0ږRy;QQ4]a2|~8_FLƅS]7*[Uogp8 ESq"+@\ KpfZTQׄ<:6}*nj!$[0D\/` 'Lep'HUgt:7jMp #V)όӋ4Dws}XF qTYʷtC}LLGY~^d֒: q1˙19/ѽwc[cpgFsĢBW\㌀{M8EC$y,f:ˤJC.W!ؼ<tő 9ZU=ݰE,hȎ>v?.~N$6)'D\Ľ~XH~foS8$Ak9I"Ez s|򅙋2~'3dA"c68Ž$IQaGt{* :P~:p%}lIfn|nSPvQ—ojm`7O  #<b)~wtIM qPTԀ(*Q'Stm@T~H^/7*X=k>k62LB.|;Z!-8s36x Ssr=. iBҾ8č,;Qj*bg,ISK6-91(^'Ћ'R}VL1[(NҗBC&ɔ.DRڡ S@D!%_mp;$qufXx1I3:Px N/bBߐXa_<;(()AD(׉nk*4L|^^ϕݣ BR)VIvxC@gȜ|B@?D&4XZ%OB/G+HZfvC:? bī"1e{[KSQXr@"k9V.tBy:'mue6B({J/Q ĭTQ))N{je:9#]6ZEgQmᗽ`1W`+k\q2mEzA9:_ ݣ]G& ڣ %Pnh:Bǂ2[aC?^$2 Y~!mʘGXA1aze5Yk( C)[ :NZE+NHh$Z-A=qL }֫#E_r[f$F dMəPg0&z*IceX$Hg23j)!Iԕ(\N'$(KgnkJRd:9yɂJG%k$f/~<(F]fFb7F9ڒ(tbhÉ)t$6zfGMzm$ i)m~{#oy$[A@YܩψM{t *#|wQyffzd>,p[BLIst;Ŋ\T؞dr\OH\s .IM7fϦM"o"jmH,׾pb>ԦP1%G$2&uh$* LIc*aooՇgou DOIa,[1t(v%#7}(( vF)%+u=Ί[O{t?kTcx 1d+$w,L!,)fÕjRɉ%Rl|( 8DH&r}N)x %+KY2MGa`gB(Ix%y+qyɂ~hkc뀾s?x{;C(tͭ^I=tR n~^كYs:gNz/1Da~û iЏ̷J^#_]J` :G;DĊ:1iAl))N$tlW& >$tۤ]9 |deOU$#sB"'|HuPᏊ(^,e7A裀HB 6 ޚyTC&P&/a)DžCL T(^u,Qm\9E= 茉axFbCCr>^m(WyEW^}lpRXE"[3zKX罖/mݱ RUծw^XԾ"{HaE"-蚷Mհ_I,8SuxA;~k~:&HDtџJiŇQq{e#1¢_uЎjڱ$zwaFl!K* _́q\+Pg0*w֗]OV%1@Db3Ñd}׊1ӣԩ %ǎN*whBOOJ|xN&A |OޱC Of@Lzj;,n7 xz<]yA%17t= ?4å_صӜ0 Ֆ:AH `Jз?|9{뽆zp[v\->"nE L\9!.iV 1u(ҷyLni潄u|l1xL1)?kխnj䝲 !ܕ|,Y:OhaUQd,+vx_k#J{p z *c3>IENDB`pydantic-pydantic-ba0aa01/docs/logos/twitter_logo.png000066400000000000000000000113771517143232300231220ustar00rootroot00000000000000PNG  IHDR/PLTE_1tRNS&Lk- !we:2p}Fɩ7Q葽[?`VGIDATxr0ж ̾%l&0`0T$C,)QRPǀ/*>J:IC^^n/g+{q]{[WQ4H>g @4鈢~O%v (}ɡ%~΋+w)'ׁꢨ{ɛV?)hB/+~V"JUQU_';v/n 1FvmゎB"j+MDQY1r%`qHU!7cwò[E~nY5ye |e,@ߕwp59#}]/Q*jYcYU;(t-&& `\VmYmIEJ%ܡAhz駴SKwaK}8f~iqސ3~9HS~1[Zm(|I1Y6,t_LU?[p3Ҙ;_ckXZ9fu_F'rpV(Wu$6*hƧ/ nCn[_Ƣ4TU'c6,W={I-]!4E,:E!6ĞYqO-"hy3a=oR,@Onfqȭ#hzqkċܨm;ȇ<1dzn|O]9u-* sjIV_kWB)Bđ|.73ػ׮T BxAM4-5osgr68 |n ؗLFTD& fdJ`TE~6 4 '0^6!޶bCj+#e>z]q8E33a/XFQa;O<:> ElHbZ4p,\&AOWvp=IeOs"`CS\&RM2$蹎M.=ye[8o-k |UՋj9eV#2T^r>ARKZv5CpYʝ~bT:}s5$s&[^vWx$kgݮb#9dA25Bj >f(JKGrQ?>M-ڒ7 iJ73XnW\<\ɺUǛ~*מƩrs"Wƅz<㡽|36A7|jag[Ʃlۮ3`hףF32XM_D)rWU}f~12lQɡ7]rHz|%!bɇ2dؕ*.:kx2_..!,zG"6W,l GNy@")娏buFЧa7'oBJ;BDj4Rv$Q'5Cqs#SN0Gޡ5;).N7+hdUԑk9C#=oM+A;TWVOs5.5Ncu7qʑ{zT3U%GZm;lS(y͛Ujiw]kɧClnWctpd"@GZYόp$ݱ!f%MtWLy@ |FmU A ڶ eA;K7~CۛQ/_{Y,CvqJY)AW@|I 'S`T vȆ!jL#H& |'$Af ٪Ʉn 5T(AO 榈#32-|#_uzV ZGzFy+A ݉V@2 KD`DM9QGcUWsmZ6z pѢ 陋Ćʳ5BBJ!˟&%ͺ25Jߺ:J mj4)SXe&x32yL.2F}YW׬ (-[755/\7FT3xWFpàzV-Wf滩sL&&J9p~ؔ>|~1AM|q f5V5$cg?fvV|(%yJt\[%'q6߱it(B1r|+Kxh Dڛ>"#_l3k(If\?yBz;k'2Ǵ:sYNkg@A̩1BعKi rVXgȟ<H\en%-gxrf5ɯZ@׈6/\[YF2P737[Y׫1MD3;л#y\Zr3"i^]o+7mےs; tɫr]);'YoӼqw)";Zg1)CCfwPc۾zjHQC3_OS ^zlgl6a>h-{"}Gf뱕%X^H2+ y߫2ZDE[˻ҮCt`Aنx2Vg[ZG*慨4_/bjrA_(3%Y xa]8ґũK擃5|fL3uݝG_!a&袚T0IENDB`pydantic-pydantic-ba0aa01/docs/logos/ukhomeoffice_logo.png000066400000000000000000000214031517143232300240530ustar00rootroot00000000000000PNG  IHDR/PLTEj5???{B~??>>A?TJtRNS͉B=zO tիIi80Y#f4܃cU^LF'Ro-*l$ۓjeHti!IDATx`vGM0 qCAG@#(ۦ%փ{ƣ; B!B!B!B!B!ͧ++ݴئ?~7Gfa=mBn>IeCQ( vݜ dBm72y0g\Bm7nZ!UwYIvj^; ٽf 9(q hYȩFG-@Z[)n=nFw2Q߭Y9n}Jft GZrEu7_9P_FwJ++I?mG96-bmY.2%M'[$帮d΁ZȆ9e6-Lky=Slgɱ3=5$*q907 y{NDb$vgzԂPA]21:"ݻV4$Hu-ɪUcs#$ޫgߺsJgޭ,\^ IyF^x\ΚUi5%`7^irDO= Qb?H -OB0:Xl<7.Yعc-t;n `J WءL Bɣ/9HZ<$OrfǘYgOdBɣ :Ynv}rczbCٌv9:wK*QT *aL/I;7ੲq6~tGħ\ISGvI#AS+A4]a+i)bfgiTczFo!әxH*6#,z;vjO2_o 0 x'W2k$];Hce0=] :&+0T"a=[*}a4txWgv'ѯMamr /@iثIz^ojN;&_O AnՑ?op.Qgn9}ݭZ=="=ޏx,r][l5-^\U. FUu3}Ein Eގ~t80ə3Ut0kP5 [63x7եm(I۫Uu@=?{tqRf$m@ߣ@K]Ya0gM7_ GGG `̗x3pChriֹ3 v9E;C.B Zvi[.?Oj{sz|q=G+=:NYSK$g/b k,^|ƅ;H# ފnӻfv_$DWK1Ymgwf\! ޼y"mX9S05i1,k|U4k5ΰ0]މfaE!#Afٟ0t5ceUOpkp3DnYlΐoDY[,169.oWj"i"P^P&+ Y}Br7x#.9Z??v)ŷnƓ}q,q(l6 ccQQg SU3;P]Zm ]cRa&؂#aJrv(O3wQC !\'Ad{9mlߴJ?3vݽѵ:L(!q/GiW Dzm&-ݑC=ڵcVrmv#}<,x946c^™mdjj\C. ]WU_[9)#U_+`,c[{? l %=Wj^}z2TC+j"%wXrTJ.)l];0 7ۡ} S)O$Wkd jt]q>UOOj΋-("1/ȼC׌>*;Eo5wÙa"G[O>3"xh*\yӧi?Jmt^U6IjMV괁Es>3ڀqΆ;ߜ9!νjVx9a7}*5|z ?hA!ԭ}G\f{5 <, dȿ56ev#'5I=zT dW7yUiPNQrV4b!-v$fö[Ko ^ ynPFm>К8SŴrr$ʹv9ySN{J"Ccp̢ޫ ^_(ԊzVFJaүF7ƮgU!#}\P\#!'D_-.#@vٱVi=ny#6bREɑ,O~T]pg}H Ȍ34;:rr`)#x e9/Je?;4sZQ Z@Ya/kOCAeibT/MjEOGjOriEƼG׏M"0ls%H"I=^~fyezQ ](G6)!'ּߝr00A@CB? J9j̥\c,R`d*=p7i,uyY\ּJOʷ*z2Ptin@Ae’@[!)?Òss“#LYF*9FD{5:d&v{C^89P>;3`T?\ɸO7t#fد"OE/< y˜)8샨T+ns|a:iKZG =aCPe+6efqjd8Ai| `!%Nml7x9Au-)\p"({$[A9 PaqgHiaC%ޭٟQ-2:E'r7F^>i xA~dEdacF?=CngvNѢ< ifײ}ףC kѷG)aUF wgL+٤sވ~|]І wAwQ=hmgr]Munv+FtH-I+!y7:tٷ4y.ODOh(46%TȡTT7z2]sv9_8 KHM@uL>x@f1tJlwɚ("noq$NO4nZۏgb}Md BKs[ Y놪ȵ>EF̵< h/J2~c):Ʊzk;Jhs#x$O \P)̏N Gt?{A QpğUR5/$V=&2+21M\0+-5־T_d9r?6a^wq*0~4:=R ?Xt YN< I?ܓGbB&N>JzaIVʑWDoFoQd'jp=- _Ubm%ʶ[cz8&S#ZA&<j"pߎ-q脷! vt֚n?yKɨeݾWPN6$F|v?0GY`+TW9]'zhNF_qli `#FpNE  ι-}o_C(CчYfΡ+DC3)T<ɼDֽ̃s$zDa葜UzhDnjidfL5rcs&:^i9uMM ϩ$T:^Lt]^piBn'F Bn'F Bn'F1^O$ 3Lnŧ^;gpB&\qg 6?SykfZϔ2݅hϭ\ǷeRsNb#mhRGQ95O^44F`% `o6Ԅ0t~|.H|x,ݠ#lP#2LLh=֦ ^|Po}D7c<_IX: #Z`+ ɍ` zoH 0hB O b<}oD&qOUp.@]#cj_$^p%i/=8rX7q<>pk珕 X|*ιF^]z;'N -n3zQ0FW~o=Zx;_81rt`K#Fn&ujW3r;L?ʝg\ SHp.uߏf$Jrځ!! ai%6OS;\ll! `3uY xݭ OM;WyقkK7}z'yJSvv%/ReZ뵞/US'8ly9<޹VuK4v,Qhy/g25Ye.[G]QFQߚf%F99o][Gr7L 2) 2i~Kp+r/+Fm+Vo؊{yuĽp2hI ȝ5r7cCd:|jG ;֏FZ(z{?u <*%qPV{p dKE`I^7#Ap0?}kѧgGI{-]- 7X[DN…J<[S5cѳW+ZO[@ugZUUW@ԭ}~eW:.wjTt&gуԤalFM+v hMDjB.Hu/%ؗ,srxs>ґKNߟ6ulֻ.5;D7Z]^i* Og0kEμຸrHLpQ4Fϣ_ϩFGOxb{`"AM:7'NDoSSẩbYj? k/?In>AjRrH9zYRP=DO]^3^p2zobu=G ӻKQ5ѻ'pu>)%z0a*{OԍN>RSsMf[83+w\[unA?DJtU;NFGپomꔥC![W/v45zCQ",}c=[mǣQCRZŕԺOuF,5ukXfspǢGϜL|zd#z]Zi߲ڿ4pE;ӏ;VӷNjJ}#ĝſ<Jך;j>NgTgOsr形{R8WS8mrhc99H{38uÁ*T78r Grb:Ԗu< k')S3ɝWY—6gUΩ+yaCY^_Ǚ@u88{\Ã=^#U^xӻAv"/ﭳPMZvp:z<=;7FwY+Ɏ[v~r#|a2jx0sэ{ݗ!Žl x$+|PhkTIxtU)m_r{{f~+5~s&+r{c5:ySp<(lyU!8Z -$qi&?<#ZSucfB8WSh 'Ctx4֋OM@ 5訶i(UåuAFgr6 .,d^jOqN6KQ8FL Jn460#ٜׄ"`h"B)4j~=YnB{0c\'.ՆaC-Ƀ hOE iT7.n?Rҿ<űZI{ ^NŒ0)dyDiECwk 0n,B=9Q )~a-ACAnV^q@(#fUjԼKXiu>7:WՁk.(_z ݃gZ Dj4]?Jx" wr\.r\؃ FPUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU@f?e5IENDB`pydantic-pydantic-ba0aa01/docs/migration.md000066400000000000000000001415631517143232300210630ustar00rootroot00000000000000--- description: Migrating from Pydantic V1. --- Pydantic V2 introduces a number of changes to the API, including some breaking changes. This page provides a guide highlighting the most important changes to help you migrate your code from Pydantic V1 to Pydantic V2. ## Install Pydantic V2 Pydantic V2 is now the current production release of Pydantic. You can install Pydantic V2 from PyPI: ```bash pip install -U pydantic ``` If you encounter any issues, please [create an issue in GitHub](https://github.com/pydantic/pydantic/issues) using the `bug V2` label. This will help us to actively monitor and track errors, and to continue to improve the library's performance. If you need to use latest Pydantic V1 for any reason, see the [Continue using Pydantic V1 features](#continue-using-pydantic-v1-features) section below for details on installation and imports from `pydantic.v1`. ## Code transformation tool We have created a tool to help you migrate your code. This tool is still in beta, but we hope it will help you to migrate your code more quickly. You can install the tool from PyPI: ```bash pip install bump-pydantic ``` The usage is simple. If your project structure is: * repo_folder * my_package * ... Then you'll want to do: cd /path/to/repo_folder bump-pydantic my_package See more about it on the [Bump Pydantic](https://github.com/pydantic/bump-pydantic) repository. ## Continue using Pydantic V1 features Pydantic V1 is still available when you need it, though we recommend migrating to Pydantic V2 for its improvements and new features. If you need to use latest Pydantic V1, you can install it with: ```bash pip install "pydantic==1.*" ``` The Pydantic V2 package also continues to provide access to the Pydantic V1 API by importing through `pydantic.v1`. For example, you can use the `BaseModel` class from Pydantic V1 instead of the Pydantic V2 `pydantic.BaseModel` class: ```python {test="skip" lint="skip" upgrade="skip"} from pydantic.v1 import BaseModel ``` You can also import functions that have been removed from Pydantic V2, such as `lenient_isinstance`: ```python {test="skip" lint="skip" upgrade="skip"} from pydantic.v1.utils import lenient_isinstance ``` Pydantic V1 documentation is available at [https://docs.pydantic.dev/1.10/](https://docs.pydantic.dev/1.10/). ### Using Pydantic v1 features in a v1/v2 environment As of `pydantic>=1.10.17`, the `pydantic.v1` namespace can be used within V1. This makes it easier to migrate to V2, which also supports the `pydantic.v1` namespace. In order to unpin a `pydantic<2` dependency and continue using V1 features, take the following steps: 1. Replace `pydantic<2` with `pydantic>=1.10.17` 2. Find and replace all occurrences of: ```python {test="skip" lint="skip" upgrade="skip"} from pydantic. import ``` with: ```python {test="skip" lint="skip" upgrade="skip"} from pydantic.v1. import ``` Here's how you can import `pydantic`'s v1 features based on your version of `pydantic`: === "`pydantic>=1.10.17,<3`" As of `v1.10.17` the `.v1` namespace is available in V1, allowing imports as below: ```python {test="skip" lint="skip" upgrade="skip"} from pydantic.v1.fields import ModelField ``` === "`pydantic<3`" All versions of Pydantic V1 and V2 support the following import pattern, in case you don't know which version of Pydantic you are using: ```python {test="skip" lint="skip" upgrade="skip"} try: from pydantic.v1.fields import ModelField except ImportError: from pydantic.fields import ModelField ``` !!! note When importing modules using `pydantic>=1.10.17,<2` with the `.v1` namespace these modules will *not* be the **same** module as the same import without the `.v1` namespace, but the symbols imported *will* be. For example `pydantic.v1.fields is not pydantic.fields` but `pydantic.v1.fields.ModelField is pydantic.fields.ModelField`. Luckily, this is not likely to be relevant in the vast majority of cases. It's just an unfortunate consequence of providing a smoother migration experience. ## Migration guide The following sections provide details on the most important changes in Pydantic V2. ### Changes to `pydantic.BaseModel` Various method names have been changed; all non-deprecated `BaseModel` methods now have names matching either the format `model_.*` or `__.*pydantic.*__`. Where possible, we have retained the deprecated methods with their old names to help ease migration, but calling them will emit `DeprecationWarning`s. | Pydantic V1 | Pydantic V2 | | ----------- | ------------ | | `__fields__` | `model_fields` | | `__private_attributes__` | `__pydantic_private__` | | `__validators__` | `__pydantic_validator__` | | `construct()` | `model_construct()` | | `copy()` | `model_copy()` | | `dict()` | `model_dump()` | | `json_schema()` | `model_json_schema()` | | `json()` | `model_dump_json()` | | `parse_obj()` | `model_validate()` | | `update_forward_refs()` | `model_rebuild()` | * Some of the built-in data-loading functionality has been slated for removal. In particular, `parse_raw` and `parse_file` are now deprecated. In Pydantic V2, `model_validate_json` works like `parse_raw`. Otherwise, you should load the data and then pass it to `model_validate`. * The `from_orm` method has been deprecated; you can now just use `model_validate` (equivalent to `parse_obj` from Pydantic V1) to achieve something similar, as long as you've set `from_attributes=True` in the model config. * The `__eq__` method has changed for models. * Models can only be equal to other `BaseModel` instances. * For two model instances to be equal, they must have the same: * Type (or, in the case of generic models, non-parametrized generic origin type) * Field values * Extra values (only relevant when `model_config['extra'] == 'allow'`) * Private attribute values; models with different values of private attributes are no longer equal. * Models are no longer equal to the dicts containing their data. * Non-generic models of different types are never equal. * Generic models with different origin types are never equal. We don't require *exact* type equality so that, for example, instances of `MyGenericModel[Any]` could be equal to instances of `MyGenericModel[int]`. * We have replaced the use of the `__root__` field to specify a "custom root model" with a new type called [`RootModel`](concepts/models.md#rootmodel-and-custom-root-types) which is intended to replace the functionality of using a field called `__root__` in Pydantic V1. Note, `RootModel` types no longer support the `arbitrary_types_allowed` config setting. See [this issue comment](https://github.com/pydantic/pydantic/issues/6710#issuecomment-1700948167) for an explanation. * We have significantly expanded Pydantic's capabilities related to customizing serialization. In particular, we have added the [`@field_serializer`](api/functional_serializers.md#pydantic.functional_serializers.field_serializer), [`@model_serializer`](api/functional_serializers.md#pydantic.functional_serializers.model_serializer), and [`@computed_field`](api/fields.md#pydantic.fields.computed_field) decorators, which each address various shortcomings from Pydantic V1. * See [Custom serializers](concepts/serialization.md#serializers) for the usage docs of these new decorators. * Due to performance overhead and implementation complexity, we have now deprecated support for specifying `json_encoders` in the model config. This functionality was originally added for the purpose of achieving custom serialization logic, and we think the new serialization decorators are a better choice in most common scenarios. * We have changed the behavior related to serializing subclasses of models when they occur as nested fields in a parent model. In V1, we would always include all fields from the subclass instance. In V2, when we dump a model, we only include the fields that are defined on the annotated type of the field. This helps prevent some accidental security bugs. You can read more about this (including how to opt out of this behavior) in the [relevant section](concepts/serialization.md#subclasses-of-model-like-types) of the model exporting docs. * `GetterDict` has been removed as it was just an implementation detail of `orm_mode`, which has been removed. * In many cases, arguments passed to the constructor will be **copied** in order to perform validation and, where necessary, coercion (see the [documentation](./concepts/models.md#attribute-copies)). This is notable in the case of passing mutable objects as arguments to a constructor. * The `.json()` method is deprecated, and attempting to use this deprecated method with arguments such as `indent` or `ensure_ascii` may lead to confusing errors. For best results, switch to V2's equivalent, `model_dump_json()`. If you'd still like to use said arguments, you can use [this workaround](https://github.com/pydantic/pydantic/issues/8825#issuecomment-1946206415). * JSON serialization of non-string key values is generally done with `str(key)`, leading to some changes in behavior such as the following: ```python {test="skip"} from typing import Optional from pydantic import BaseModel as V2BaseModel from pydantic.v1 import BaseModel as V1BaseModel class V1Model(V1BaseModel): a: dict[Optional[str], int] class V2Model(V2BaseModel): a: dict[Optional[str], int] v1_model = V1Model(a={None: 123}) v2_model = V2Model(a={None: 123}) # V1 print(v1_model.json()) #> {"a": {"null": 123}} # V2 print(v2_model.model_dump_json()) #> {"a":{"None":123}} ``` * `model_dump_json()` results are compacted in order to save space, and don't always exactly match that of `json.dumps()` output. That being said, you can easily modify the separators used in `json.dumps()` results in order to align the two outputs: ```python {test="skip"} import json from pydantic import BaseModel as V2BaseModel from pydantic.v1 import BaseModel as V1BaseModel class V1Model(V1BaseModel): a: list[str] class V2Model(V2BaseModel): a: list[str] v1_model = V1Model(a=['fancy', 'sushi']) v2_model = V2Model(a=['fancy', 'sushi']) # V1 print(v1_model.json()) #> {"a": ["fancy", "sushi"]} # V2 print(v2_model.model_dump_json()) #> {"a":["fancy","sushi"]} # Plain json.dumps print(json.dumps(v2_model.model_dump())) #> {"a": ["fancy", "sushi"]} # Modified json.dumps print(json.dumps(v2_model.model_dump(), separators=(',', ':'))) #> {"a":["fancy","sushi"]} ``` ### Changes to `pydantic.generics.GenericModel` The `pydantic.generics.GenericModel` class is no longer necessary, and has been removed. Instead, you can now create generic `BaseModel` subclasses by just adding `Generic` as a parent class on a `BaseModel` subclass directly. This looks like `class MyGenericModel(BaseModel, Generic[T]): ...`. Mixing of V1 and V2 models is not supported which means that type parameters of such generic `BaseModel` (V2) cannot be V1 models. While it may not raise an error, we strongly advise against using *parametrized* generics in `isinstance` checks. * For example, you should not do `isinstance(my_model, MyGenericModel[int])`. However, it is fine to do `isinstance(my_model, MyGenericModel)`. (Note that for standard generics, it would raise an error to do a subclass check with a parameterized generic.) * If you need to perform `isinstance` checks against parametrized generics, you can do this by subclassing the parametrized generic class. This looks like `class MyIntModel(MyGenericModel[int]): ...` and `isinstance(my_model, MyIntModel)`. Find more information in the [Generic models](concepts/models.md#generic-models) documentation. ### Changes to `pydantic.Field` `Field` no longer supports arbitrary keyword arguments to be added to the JSON schema. Instead, any extra data you want to add to the JSON schema should be passed as a dictionary to the `json_schema_extra` keyword argument. In Pydantic V1, the `alias` property returns the field's name when no alias is set. In Pydantic V2, this behavior has changed to return `None` when no alias is set. The following properties have been removed from or changed in `Field`: * `const` * `min_items` (use `min_length` instead) * `max_items` (use `max_length` instead) * `unique_items` * `allow_mutation` (use `frozen` instead) * `regex` (use `pattern` instead) * `final` (use the [typing.Final][] type hint instead) Field constraints are no longer automatically pushed down to the parameters of generics. For example, you can no longer validate every element of a list matches a regex by providing `my_list: list[str] = Field(pattern=".*")`. Instead, use [`typing.Annotated`][] to provide an annotation on the `str` itself: `my_list: list[Annotated[str, Field(pattern=".*")]]` ### Changes to dataclasses Pydantic [dataclasses](concepts/dataclasses.md) continue to be useful for enabling the data validation on standard dataclasses without having to subclass `BaseModel`. Pydantic V2 introduces the following changes to this dataclass behavior: * When used as fields, dataclasses (Pydantic or vanilla) no longer accept tuples as validation inputs; dicts should be used instead. * The `__post_init__` in Pydantic dataclasses will now be called *after* validation, rather than before. * As a result, the `__post_init_post_parse__` method would have become redundant, so has been removed. * Pydantic no longer supports `extra='allow'` for Pydantic dataclasses, where extra fields passed to the initializer would be stored as extra attributes on the dataclass. `extra='ignore'` is still supported for the purpose of ignoring unexpected fields while parsing data, they just won't be stored on the instance. * Pydantic dataclasses no longer have an attribute `__pydantic_model__`, and no longer use an underlying `BaseModel` to perform validation or provide other functionality. * To perform validation, generate a JSON schema, or make use of any other functionality that may have required `__pydantic_model__` in V1, you should now wrap the dataclass with a [`TypeAdapter`][pydantic.type_adapter.TypeAdapter] ([discussed more below](#introduction-of-typeadapter)) and make use of its methods. * In Pydantic V1, if you used a vanilla (i.e., non-Pydantic) dataclass as a field, the config of the parent type would be used as though it was the config for the dataclass itself as well. In Pydantic V2, this is no longer the case. * In Pydantic V2, to override the config (like you would with `model_config` on a `BaseModel`), you can use the `config` parameter on the `@dataclass` decorator. See [Dataclass Config](concepts/dataclasses.md#dataclass-config) for examples. ### Changes to config * In Pydantic V2, to specify config on a model, you should set a class attribute called `model_config` to be a dict with the key/value pairs you want to be used as the config. The Pydantic V1 behavior to create a class called `Config` in the namespace of the parent `BaseModel` subclass is now deprecated. * When subclassing a model, the `model_config` attribute is inherited. This is helpful in the case where you'd like to use a base class with a given configuration for many models. Note, if you inherit from multiple `BaseModel` subclasses, like `class MyModel(Model1, Model2)`, the non-default settings in the `model_config` attribute from the two models will be merged, and for any settings defined in both, those from `Model2` will override those from `Model1`. * The following config settings have been removed: * `allow_mutation` — this has been removed. You should be able to use [frozen](api/config.md#pydantic.config.ConfigDict) equivalently (inverse of current use). * `error_msg_templates` * `fields` — this was the source of various bugs, so has been removed. You should be able to use `Annotated` on fields to modify them as desired. * `getter_dict` — `orm_mode` has been removed, and this implementation detail is no longer necessary. * `smart_union` - the default `union_mode` in Pydantic V2 is `'smart'`. * `underscore_attrs_are_private` — the Pydantic V2 behavior is now the same as if this was always set to `True` in Pydantic V1. * `json_loads` * `json_dumps` * `copy_on_model_validation` * `post_init_call` * The following config settings have been renamed: * `allow_population_by_field_name` → `populate_by_name` (or `validate_by_name` starting in v2.11) * `anystr_lower` → `str_to_lower` * `anystr_strip_whitespace` → `str_strip_whitespace` * `anystr_upper` → `str_to_upper` * `keep_untouched` → `ignored_types` * `max_anystr_length` → `str_max_length` * `min_anystr_length` → `str_min_length` * `orm_mode` → `from_attributes` * `schema_extra` → `json_schema_extra` * `validate_all` → `validate_default` See the [`ConfigDict` API reference][pydantic.config.ConfigDict] for more details. ### Changes to validators #### `@validator` and `@root_validator` are deprecated * `@validator` has been deprecated, and should be replaced with [`@field_validator`](concepts/validators.md), which provides various new features and improvements. * The new `@field_validator` decorator does not have the `each_item` keyword argument; validators you want to apply to items within a generic container should be added by annotating the type argument. See [validators in Annotated metadata](concepts/types.md#using-the-annotated-pattern) for details. This looks like `list[Annotated[int, Field(ge=0)]]` * Even if you keep using the deprecated `@validator` decorator, you can no longer add the `field` or `config` arguments to the signature of validator functions. If you need access to these, you'll need to migrate to `@field_validator` — see the [next section](#changes-to-validators-allowed-signatures) for more details. * If you use the `always=True` keyword argument to a validator function, note that standard validators for the annotated type will *also* be applied even to defaults, not just the custom validators. For example, despite the fact that the validator below will never error, the following code raises a `ValidationError`: !!! note To avoid this, you can use the `validate_default` argument in the `Field` function. When set to `True`, it mimics the behavior of `always=True` in Pydantic v1. However, the new way of using `validate_default` is encouraged as it provides more flexibility and control. ```python {test="skip"} from pydantic import BaseModel, validator class Model(BaseModel): x: str = 1 @validator('x', always=True) @classmethod def validate_x(cls, v): return v Model() ``` * `@root_validator` has been deprecated, and should be replaced with [`@model_validator`](api/functional_validators.md#pydantic.functional_validators.model_validator), which also provides new features and improvements. Be aware that the allowed signatures have changed (see the [relevant documentation](./concepts/validators.md#model-validators)). * Under some circumstances (such as assignment when `model_config['validate_assignment'] is True`), the `@model_validator` decorator will receive an instance of the model, not a dict of values. You may need to be careful to handle this case. * Even if you keep using the deprecated `@root_validator` decorator, due to refactors in validation logic, you can no longer run with `skip_on_failure=False` (which is the default value of this keyword argument, so must be set explicitly to `True`). #### Changes to `@validator`'s allowed signatures In Pydantic V1, functions wrapped by `@validator` could receive keyword arguments with metadata about what was being validated. Some of these arguments have been removed from `@field_validator` in Pydantic V2: * `config`: Pydantic V2's config is now a dictionary instead of a class, which means this argument is no longer backwards compatible. If you need to access the configuration you should migrate to `@field_validator` and use `info.config`. * `field`: this argument used to be a `ModelField` object, which was a quasi-internal class that no longer exists in Pydantic V2. Most of this information can still be accessed by using the field name from `info.field_name` to index into `cls.model_fields` ```python from pydantic import BaseModel, ValidationInfo, field_validator class Model(BaseModel): x: int @field_validator('x') def val_x(cls, v: int, info: ValidationInfo) -> int: assert info.config is not None print(info.config.get('title')) #> Model print(cls.model_fields[info.field_name].is_required()) #> True return v Model(x=1) ``` #### `TypeError` is no longer converted to `ValidationError` in validators Previously, when raising a `TypeError` within a validator function, that error would be wrapped into a `ValidationError` and, in some cases (such as with FastAPI), these errors might be displayed to end users. This led to a variety of undesirable behavior — for example, calling a function with the wrong signature might produce a user-facing `ValidationError`. However, in Pydantic V2, when a `TypeError` is raised in a validator, it is no longer converted into a `ValidationError`: ```python import pytest from pydantic import BaseModel, field_validator class Model(BaseModel): x: int @field_validator('x') def val_x(cls, v: int) -> int: return str.lower(v) # raises a TypeError with pytest.raises(TypeError): Model(x=1) ``` This applies to all validation decorators. #### Validator behavior changes Pydantic V2 includes some changes to type coercion. For example: * coercing `int`, `float`, and `Decimal` values to strings is now optional and disabled by default, see [Coerce Numbers to Strings][pydantic.config.ConfigDict.coerce_numbers_to_str]. * iterable of pairs is no longer coerced to a dict. See the [Conversion table](concepts/conversion_table.md) for details on Pydantic V2 type coercion defaults. #### The `allow_reuse` keyword argument is no longer necessary Previously, Pydantic tracked "reused" functions in decorators as this was a common source of mistakes. We did this by comparing the function's fully qualified name (module name + function name), which could result in false positives. The `allow_reuse` keyword argument could be used to disable this when it was intentional. Our approach to detecting repeatedly defined functions has been overhauled to only error for redefinition within a single class, reducing false positives and bringing the behavior more in line with the errors that type checkers and linters would give for defining a method with the same name multiple times in a single class definition. In nearly all cases, if you were using `allow_reuse=True`, you should be able to simply delete that keyword argument and have things keep working as expected. #### `@validate_arguments` has been renamed to `@validate_call` In Pydantic V2, the `@validate_arguments` decorator has been renamed to `@validate_call`. In Pydantic V1, the decorated function had various attributes added, such as `raw_function`, and `validate` (which could be used to validate arguments without actually calling the decorated function). Due to limited use of these attributes, and performance-oriented changes in implementation, we have not preserved this functionality in `@validate_call`. ### Input types are not preserved In Pydantic V1 we made great efforts to preserve the types of all field inputs for generic collections when they were proper subtypes of the field annotations. For example, given the annotation `Mapping[str, int]` if you passed in a `collection.Counter()` you'd get a `collection.Counter()` as the value. Supporting this behavior in V2 would have negative performance implications for the general case (we'd have to check types every time) and would add a lot of complexity to validation. Further, even in V1 this behavior was inconsistent and partially broken: it did not work for many types (`str`, `UUID`, etc.), and for generic collections it's impossible to re-build the original input correctly without a lot of special casing (consider `ChainMap`; rebuilding the input is necessary because we need to replace values after validation, e.g. if coercing strings to ints). In Pydantic V2 we no longer attempt to preserve the input type in all cases; instead, we only promise that the output type will match the type annotations. Going back to the `Mapping` example, we promise the output will be a valid `Mapping`, and in practice it will be a plain `dict`: ```python from collections.abc import Mapping from pydantic import TypeAdapter class MyDict(dict): pass ta = TypeAdapter(Mapping[str, int]) v = ta.validate_python(MyDict()) print(type(v)) #> ``` If you want the output type to be a specific type, consider annotating it as such or implementing a custom validator: ```python from collections.abc import Mapping from typing import Annotated, Any, TypeVar from pydantic import ( TypeAdapter, ValidationInfo, ValidatorFunctionWrapHandler, WrapValidator, ) def restore_input_type( value: Any, handler: ValidatorFunctionWrapHandler, _info: ValidationInfo ) -> Any: return type(value)(handler(value)) T = TypeVar('T') PreserveType = Annotated[T, WrapValidator(restore_input_type)] ta = TypeAdapter(PreserveType[Mapping[str, int]]) class MyDict(dict): pass v = ta.validate_python(MyDict()) assert type(v) is MyDict ``` While we don't promise to preserve input types everywhere, we *do* preserve them for subclasses of `BaseModel`, and for dataclasses: ```python import pydantic.dataclasses from pydantic import BaseModel class InnerModel(BaseModel): x: int class OuterModel(BaseModel): inner: InnerModel class SubInnerModel(InnerModel): y: int m = OuterModel(inner=SubInnerModel(x=1, y=2)) print(m) #> inner=SubInnerModel(x=1, y=2) @pydantic.dataclasses.dataclass class InnerDataclass: x: int @pydantic.dataclasses.dataclass class SubInnerDataclass(InnerDataclass): y: int @pydantic.dataclasses.dataclass class OuterDataclass: inner: InnerDataclass d = OuterDataclass(inner=SubInnerDataclass(x=1, y=2)) print(d) #> OuterDataclass(inner=SubInnerDataclass(x=1, y=2)) ``` ### Changes to Handling of Standard Types #### Dicts Iterables of pairs (which include empty iterables) no longer pass validation for fields of type `dict`. #### Unions While union types will still attempt validation of each choice from left to right, they now preserve the type of the input whenever possible, even if the correct type is not the first choice for which the input would pass validation. As a demonstration, consider the following example: ```python from typing import Union from pydantic import BaseModel class Model(BaseModel): x: Union[int, str] print(Model(x='1')) #> x='1' ``` In Pydantic V1, the printed result would have been `x=1`, since the value would pass validation as an `int`. In Pydantic V2, we recognize that the value is an instance of one of the cases and short-circuit the standard union validation. To revert to the non-short-circuiting left-to-right behavior of V1, annotate the union with `Field(union_mode='left_to_right')`. See [Union Mode](./concepts/unions.md#union-modes) for more details. #### Required, optional, and nullable fields Pydantic V2 changes some of the logic for specifying whether a field annotated as `Optional` is required (i.e., has no default value) or not (i.e., has a default value of `None` or any other value of the corresponding type), and now more closely matches the behavior of `dataclasses`. Similarly, fields annotated as `Any` no longer have a default value of `None`. The following table describes the behavior of field annotations in V2: | State | Field Definition | |-------------------------------------------------------|-----------------------------| | Required, cannot be `None` | `f1: str` | | Not required, cannot be `None`, is `'abc'` by default | `f2: str = 'abc'` | | Required, can be `None` | `f3: Optional[str]` | | Not required, can be `None`, is `None` by default | `f4: Optional[str] = None` | | Not required, can be `None`, is `'abc'` by default | `f5: Optional[str] = 'abc'` | | Required, can be any type (including `None`) | `f6: Any` | | Not required, can be any type (including `None`) | `f7: Any = None` | !!! note A field annotated as `typing.Optional[T]` will be required, and will allow for a value of `None`. It does not mean that the field has a default value of `None`. *(This is a breaking change from V1.)* !!! note Any default value if provided makes a field not required. Here is a code example demonstrating the above: ```python from typing import Optional from pydantic import BaseModel, ValidationError class Foo(BaseModel): f1: str # required, cannot be None f2: Optional[str] # required, can be None - same as str | None f3: Optional[str] = None # not required, can be None f4: str = 'Foobar' # not required, but cannot be None try: Foo(f1=None, f2=None, f4='b') except ValidationError as e: print(e) """ 1 validation error for Foo f1 Input should be a valid string [type=string_type, input_value=None, input_type=NoneType] """ ``` #### Patterns / regex on strings Pydantic V1 used Python's regex library. Pydantic V2 uses the Rust [regex crate]. This crate is not just a "Rust version of regular expressions", it's a completely different approach to regular expressions. In particular, it promises linear time searching of strings in exchange for dropping a couple of features (namely look arounds and backreferences). We believe this is a tradeoff worth making, in particular because Pydantic is used to validate untrusted input where ensuring things don't accidentally run in exponential time depending on the untrusted input is important. On the flipside, for anyone not using these features complex regex validation should be orders of magnitude faster because it's done in Rust and in linear time. If you still want to use Python's regex library, you can use the [`regex_engine`](./api/config.md#pydantic.config.ConfigDict.regex_engine) config setting. [regex crate]: https://github.com/rust-lang/regex ### Type conversion from floats to integers In V1, whenever a field was annotated as `int`, any float value would be accepted, which could lead to a potential data loss if the float value contains a non-zero decimal part. In V2, type conversion from floats to integers is only allowed if the decimal part is zero: ```python from pydantic import BaseModel, ValidationError class Model(BaseModel): x: int print(Model(x=10.0)) #> x=10 try: Model(x=10.2) except ValidationError as err: print(err) """ 1 validation error for Model x Input should be a valid integer, got a number with a fractional part [type=int_from_float, input_value=10.2, input_type=float] """ ``` ### Introduction of `TypeAdapter` Pydantic V1 had weak support for validating or serializing non-`BaseModel` types. To work with them, you had to either create a "root" model or use the utility functions in `pydantic.tools` (namely, `parse_obj_as` and `schema_of`). In Pydantic V2 this is *a lot* easier: the [`TypeAdapter`][pydantic.type_adapter.TypeAdapter] class lets you create an object with methods for validating, serializing, and producing JSON schemas for arbitrary types. This serves as a complete replacement for `parse_obj_as` and `schema_of` (which are now deprecated), and also covers some of the use cases of "root" models. ([`RootModel`](concepts/models.md#rootmodel-and-custom-root-types), [discussed above](#changes-to-pydanticbasemodel), covers the others.) ```python from pydantic import TypeAdapter adapter = TypeAdapter(list[int]) assert adapter.validate_python(['1', '2', '3']) == [1, 2, 3] print(adapter.json_schema()) #> {'items': {'type': 'integer'}, 'type': 'array'} ``` Due to limitations of inferring generic types with common type checkers, to get proper typing in some scenarios, you may need to explicitly specify the generic parameter: ```python {test="skip"} from pydantic import TypeAdapter adapter = TypeAdapter[str | int](str | int) ... ``` See [Type Adapter](concepts/type_adapter.md) for more information. ### Defining custom types We have completely overhauled the way custom types are defined in pydantic. We have exposed hooks for generating both `pydantic-core` and JSON schemas, allowing you to get all the performance benefits of Pydantic V2 even when using your own custom types. We have also introduced ways to use [`typing.Annotated`][] to add custom validation to your own types. The main changes are: * `__get_validators__` should be replaced with `__get_pydantic_core_schema__`. See [Custom Data Types](concepts/types.md#customizing_validation_with_get_pydantic_core_schema) for more information. * `__modify_schema__` becomes `__get_pydantic_json_schema__`. See [JSON Schema Customization](concepts/json_schema.md#customizing-json-schema) for more information. Additionally, you can use [`typing.Annotated`][] to modify or provide the `__get_pydantic_core_schema__` and `__get_pydantic_json_schema__` functions of a type by annotating it, rather than modifying the type itself. This provides a powerful and flexible mechanism for integrating third-party types with Pydantic, and in some cases may help you remove hacks from Pydantic V1 introduced to work around the limitations for custom types. See [Custom Data Types](concepts/types.md#custom-types) for more information. ### Changes to JSON schema generation We received many requests over the years to make changes to the JSON schemas that pydantic generates. In Pydantic V2, we have tried to address many of the common requests: * The JSON schema for `Optional` fields now indicates that the value `null` is allowed. * The `Decimal` type is now exposed in JSON schema (and serialized) as a string. * The JSON schema no longer preserves namedtuples as namedtuples. * The JSON schema we generate by default now targets draft 2020-12 (with some OpenAPI extensions). * When they differ, you can now specify if you want the JSON schema representing the inputs to validation, or the outputs from serialization. However, there have been many reasonable requests over the years for changes which we have not chosen to implement. In Pydantic V1, even if you were willing to implement changes yourself, it was very difficult because the JSON schema generation process involved various recursive function calls; to override one, you'd have to copy and modify the whole implementation. In Pydantic V2, one of our design goals was to make it easier to customize JSON schema generation. To this end, we have introduced the class [`GenerateJsonSchema`](api/json_schema.md#pydantic.json_schema.GenerateJsonSchema), which implements the translation of a type's pydantic-core schema into a JSON schema. By design, this class breaks the JSON schema generation process into smaller methods that can be easily overridden in subclasses to modify the "global" approach to generating JSON schema. The various methods that can be used to produce JSON schema (such as `BaseModel.model_json_schema` or `TypeAdapter.json_schema`) accept a keyword argument `schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema`, and you can pass your custom subclass to these methods in order to use your own approach to generating JSON schema. Hopefully this means that if you disagree with any of the choices we've made, or if you are reliant on behaviors in Pydantic V1 that have changed in Pydantic V2, you can use a custom `schema_generator`, modifying the `GenerateJsonSchema` class as necessary for your application. ### `BaseSettings` has moved to `pydantic-settings` [`BaseSettings`](api/pydantic_settings.md#pydantic_settings.BaseSettings), the base object for Pydantic [settings management](concepts/pydantic_settings.md), has been moved to a separate package, [`pydantic-settings`](https://github.com/pydantic/pydantic-settings). Also, the `parse_env_var` classmethod has been removed. So, you need to [customise settings sources](concepts/pydantic_settings.md#customise-settings-sources) to have your own parsing function. ### Color and Payment Card Numbers moved to `pydantic-extra-types` The following special-use types have been moved to the [Pydantic Extra Types](https://github.com/pydantic/pydantic-extra-types) package, which may be installed separately if needed. * [Color Types](api/pydantic_extra_types_color.md) * [Payment Card Numbers](api/pydantic_extra_types_payment.md) ### Url and Dsn types in `pydantic.networks` no longer inherit from `str` In Pydantic V1 the [`AnyUrl`][pydantic.networks.AnyUrl] type inherited from `str`, and all the other `Url` and `Dsn` types inherited from these. In Pydantic V2 these types are built on two new `Url` and `MultiHostUrl` classes using `Annotated`. Inheriting from `str` had upsides and downsides, and for V2 we decided it would be better to remove this. To use these types in APIs which expect `str` you'll now need to convert them (with `str(url)`). Pydantic V2 uses Rust's [Url](https://crates.io/crates/url) crate for URL validation. Some of the URL validation differs slightly from the previous behavior in V1. One notable difference is that the new `Url` types append slashes to the validated version if no path is included, even if a slash is not specified in the argument to a `Url` type constructor. See the example below for this behavior: ```python from pydantic import AnyUrl assert str(AnyUrl(url='https://google.com')) == 'https://google.com/' assert str(AnyUrl(url='https://google.com/')) == 'https://google.com/' assert str(AnyUrl(url='https://google.com/api')) == 'https://google.com/api' assert str(AnyUrl(url='https://google.com/api/')) == 'https://google.com/api/' ``` If you still want to use the old behavior without the appended slash, take a look at this [solution](https://github.com/pydantic/pydantic/issues/7186#issuecomment-1690235887). ### Constrained types The `Constrained*` classes were *removed*, and you should replace them by `Annotated[, Field(...)]`, for example: ```python {test="skip"} from pydantic import BaseModel, ConstrainedInt class MyInt(ConstrainedInt): ge = 0 class Model(BaseModel): x: MyInt ``` ...becomes: ```python from typing import Annotated from pydantic import BaseModel, Field MyInt = Annotated[int, Field(ge=0)] class Model(BaseModel): x: MyInt ``` Read more about it in the [Composing types via `Annotated`](concepts/types.md#using-the-annotated-pattern) docs. For `ConstrainedStr` you can use [`StringConstraints`][pydantic.types.StringConstraints] instead. ### Mypy plugins Pydantic V2 contains a [mypy](https://mypy.readthedocs.io/en/stable/extending_mypy.html#configuring-mypy-to-use-plugins) plugin in `pydantic.mypy`. When using [V1 features](migration.md#continue-using-pydantic-v1-features) the `pydantic.v1.mypy` plugin might need to also be enabled. To configure the mypy plugins: === "`mypy.ini`" ```ini [mypy] plugins = pydantic.mypy, pydantic.v1.mypy # include `.v1.mypy` if required. ``` === "`pyproject.toml`" ```toml [tool.mypy] plugins = [ "pydantic.mypy", "pydantic.v1.mypy", # include `.v1.mypy` if required. ] ``` ## Other changes * Dropped support for [`email-validator<2.0.0`](https://github.com/JoshData/python-email-validator). Make sure to update using `pip install -U email-validator`. ## Moved in Pydantic V2 | Pydantic V1 | Pydantic V2 | | --- | --- | | `pydantic.BaseSettings` | [`pydantic_settings.BaseSettings`](#basesettings-has-moved-to-pydantic-settings) | | `pydantic.color` | [`pydantic_extra_types.color`][pydantic_extra_types.color] | | `pydantic.types.PaymentCardBrand` | [`pydantic_extra_types.PaymentCardBrand`](#color-and-payment-card-numbers-moved-to-pydantic-extra-types) | | `pydantic.types.PaymentCardNumber` | [`pydantic_extra_types.PaymentCardNumber`](#color-and-payment-card-numbers-moved-to-pydantic-extra-types) | | `pydantic.utils.version_info` | [`pydantic.version.version_info`][pydantic.version.version_info] | | `pydantic.error_wrappers.ValidationError` | [`pydantic.ValidationError`][pydantic_core.ValidationError] | | `pydantic.utils.to_camel` | [`pydantic.alias_generators.to_pascal`][pydantic.alias_generators.to_pascal] | | `pydantic.utils.to_lower_camel` | [`pydantic.alias_generators.to_camel`][pydantic.alias_generators.to_camel] | | `pydantic.PyObject` | [`pydantic.ImportString`][pydantic.types.ImportString] | ## Deprecated and moved in Pydantic V2 | Pydantic V1 | Pydantic V2 | | --- | --- | | `pydantic.tools.schema_of` | `pydantic.deprecated.tools.schema_of` | | `pydantic.tools.parse_obj_as` | `pydantic.deprecated.tools.parse_obj_as` | | `pydantic.tools.schema_json_of` | `pydantic.deprecated.tools.schema_json_of` | | `pydantic.json.pydantic_encoder` | `pydantic.deprecated.json.pydantic_encoder` | | `pydantic.validate_arguments` | `pydantic.deprecated.decorator.validate_arguments` | | `pydantic.json.custom_pydantic_encoder` | `pydantic.deprecated.json.custom_pydantic_encoder` | | `pydantic.json.ENCODERS_BY_TYPE` | `pydantic.deprecated.json.ENCODERS_BY_TYPE` | | `pydantic.json.timedelta_isoformat` | `pydantic.deprecated.json.timedelta_isoformat` | | `pydantic.decorator.validate_arguments` | `pydantic.deprecated.decorator.validate_arguments` | | `pydantic.class_validators.validator` | `pydantic.deprecated.class_validators.validator` | | `pydantic.class_validators.root_validator` | `pydantic.deprecated.class_validators.root_validator` | | `pydantic.utils.deep_update` | `pydantic.v1.utils.deep_update` | | `pydantic.utils.GetterDict` | `pydantic.v1.utils.GetterDict` | | `pydantic.utils.lenient_issubclass` | `pydantic.v1.utils.lenient_issubclass` | | `pydantic.utils.lenient_isinstance` | `pydantic.v1.utils.lenient_isinstance` | | `pydantic.utils.is_valid_field` | `pydantic.v1.utils.is_valid_field` | | `pydantic.utils.update_not_none` | `pydantic.v1.utils.update_not_none` | | `pydantic.utils.import_string` | `pydantic.v1.utils.import_string` | | `pydantic.utils.Representation` | `pydantic.v1.utils.Representation` | | `pydantic.utils.ROOT_KEY` | `pydantic.v1.utils.ROOT_KEY` | | `pydantic.utils.smart_deepcopy` | `pydantic.v1.utils.smart_deepcopy` | | `pydantic.utils.sequence_like` | `pydantic.v1.utils.sequence_like` | ## Removed in Pydantic V2 * `pydantic.ConstrainedBytes` * `pydantic.ConstrainedDate` * `pydantic.ConstrainedDecimal` * `pydantic.ConstrainedFloat` * `pydantic.ConstrainedFrozenSet` * `pydantic.ConstrainedInt` * `pydantic.ConstrainedList` * `pydantic.ConstrainedSet` * `pydantic.ConstrainedStr` * `pydantic.JsonWrapper` * `pydantic.NoneBytes` * This was an alias to `None | bytes`. * `pydantic.NoneStr` * This was an alias to `None | str`. * `pydantic.NoneStrBytes` * This was an alias to `None | str | bytes`. * `pydantic.Protocol` * `pydantic.Required` * `pydantic.StrBytes` * This was an alias to `str | bytes`. * `pydantic.compiled` * `pydantic.config.get_config` * `pydantic.config.inherit_config` * `pydantic.config.prepare_config` * `pydantic.create_model_from_namedtuple` * `pydantic.create_model_from_typeddict` * `pydantic.dataclasses.create_pydantic_model_from_dataclass` * `pydantic.dataclasses.make_dataclass_validator` * `pydantic.dataclasses.set_validation` * `pydantic.datetime_parse.parse_date` * `pydantic.datetime_parse.parse_time` * `pydantic.datetime_parse.parse_datetime` * `pydantic.datetime_parse.parse_duration` * `pydantic.error_wrappers.ErrorWrapper` * `pydantic.errors.AnyStrMaxLengthError` * `pydantic.errors.AnyStrMinLengthError` * `pydantic.errors.ArbitraryTypeError` * `pydantic.errors.BoolError` * `pydantic.errors.BytesError` * `pydantic.errors.CallableError` * `pydantic.errors.ClassError` * `pydantic.errors.ColorError` * `pydantic.errors.ConfigError` * `pydantic.errors.DataclassTypeError` * `pydantic.errors.DateError` * `pydantic.errors.DateNotInTheFutureError` * `pydantic.errors.DateNotInThePastError` * `pydantic.errors.DateTimeError` * `pydantic.errors.DecimalError` * `pydantic.errors.DecimalIsNotFiniteError` * `pydantic.errors.DecimalMaxDigitsError` * `pydantic.errors.DecimalMaxPlacesError` * `pydantic.errors.DecimalWholeDigitsError` * `pydantic.errors.DictError` * `pydantic.errors.DurationError` * `pydantic.errors.EmailError` * `pydantic.errors.EnumError` * `pydantic.errors.EnumMemberError` * `pydantic.errors.ExtraError` * `pydantic.errors.FloatError` * `pydantic.errors.FrozenSetError` * `pydantic.errors.FrozenSetMaxLengthError` * `pydantic.errors.FrozenSetMinLengthError` * `pydantic.errors.HashableError` * `pydantic.errors.IPv4AddressError` * `pydantic.errors.IPv4InterfaceError` * `pydantic.errors.IPv4NetworkError` * `pydantic.errors.IPv6AddressError` * `pydantic.errors.IPv6InterfaceError` * `pydantic.errors.IPv6NetworkError` * `pydantic.errors.IPvAnyAddressError` * `pydantic.errors.IPvAnyInterfaceError` * `pydantic.errors.IPvAnyNetworkError` * `pydantic.errors.IntEnumError` * `pydantic.errors.IntegerError` * `pydantic.errors.InvalidByteSize` * `pydantic.errors.InvalidByteSizeUnit` * `pydantic.errors.InvalidDiscriminator` * `pydantic.errors.InvalidLengthForBrand` * `pydantic.errors.JsonError` * `pydantic.errors.JsonTypeError` * `pydantic.errors.ListError` * `pydantic.errors.ListMaxLengthError` * `pydantic.errors.ListMinLengthError` * `pydantic.errors.ListUniqueItemsError` * `pydantic.errors.LuhnValidationError` * `pydantic.errors.MissingDiscriminator` * `pydantic.errors.MissingError` * `pydantic.errors.NoneIsAllowedError` * `pydantic.errors.NoneIsNotAllowedError` * `pydantic.errors.NotDigitError` * `pydantic.errors.NotNoneError` * `pydantic.errors.NumberNotGeError` * `pydantic.errors.NumberNotGtError` * `pydantic.errors.NumberNotLeError` * `pydantic.errors.NumberNotLtError` * `pydantic.errors.NumberNotMultipleError` * `pydantic.errors.PathError` * `pydantic.errors.PathNotADirectoryError` * `pydantic.errors.PathNotAFileError` * `pydantic.errors.PathNotExistsError` * `pydantic.errors.PatternError` * `pydantic.errors.PyObjectError` * `pydantic.errors.PydanticTypeError` * `pydantic.errors.PydanticValueError` * `pydantic.errors.SequenceError` * `pydantic.errors.SetError` * `pydantic.errors.SetMaxLengthError` * `pydantic.errors.SetMinLengthError` * `pydantic.errors.StrError` * `pydantic.errors.StrRegexError` * `pydantic.errors.StrictBoolError` * `pydantic.errors.SubclassError` * `pydantic.errors.TimeError` * `pydantic.errors.TupleError` * `pydantic.errors.TupleLengthError` * `pydantic.errors.UUIDError` * `pydantic.errors.UUIDVersionError` * `pydantic.errors.UrlError` * `pydantic.errors.UrlExtraError` * `pydantic.errors.UrlHostError` * `pydantic.errors.UrlHostTldError` * `pydantic.errors.UrlPortError` * `pydantic.errors.UrlSchemeError` * `pydantic.errors.UrlSchemePermittedError` * `pydantic.errors.UrlUserInfoError` * `pydantic.errors.WrongConstantError` * `pydantic.main.validate_model` * `pydantic.networks.stricturl` * `pydantic.parse_file_as` * `pydantic.parse_raw_as` * `pydantic.stricturl` * `pydantic.tools.parse_file_as` * `pydantic.tools.parse_raw_as` * `pydantic.types.JsonWrapper` * `pydantic.types.NoneBytes` * `pydantic.types.NoneStr` * `pydantic.types.NoneStrBytes` * `pydantic.types.PyObject` * `pydantic.types.StrBytes` * `pydantic.typing.evaluate_forwardref` * `pydantic.typing.AbstractSetIntStr` * `pydantic.typing.AnyCallable` * `pydantic.typing.AnyClassMethod` * `pydantic.typing.CallableGenerator` * `pydantic.typing.DictAny` * `pydantic.typing.DictIntStrAny` * `pydantic.typing.DictStrAny` * `pydantic.typing.IntStr` * `pydantic.typing.ListStr` * `pydantic.typing.MappingIntStrAny` * `pydantic.typing.NoArgAnyCallable` * `pydantic.typing.NoneType` * `pydantic.typing.ReprArgs` * `pydantic.typing.SetStr` * `pydantic.typing.StrPath` * `pydantic.typing.TupleGenerator` * `pydantic.typing.WithArgsTypes` * `pydantic.typing.all_literal_values` * `pydantic.typing.display_as_type` * `pydantic.typing.get_all_type_hints` * `pydantic.typing.get_args` * `pydantic.typing.get_origin` * `pydantic.typing.get_sub_types` * `pydantic.typing.is_callable_type` * `pydantic.typing.is_classvar` * `pydantic.typing.is_finalvar` * `pydantic.typing.is_literal_type` * `pydantic.typing.is_namedtuple` * `pydantic.typing.is_new_type` * `pydantic.typing.is_none_type` * `pydantic.typing.is_typeddict` * `pydantic.typing.is_typeddict_special` * `pydantic.typing.is_union` * `pydantic.typing.new_type_supertype` * `pydantic.typing.resolve_annotations` * `pydantic.typing.typing_base` * `pydantic.typing.update_field_forward_refs` * `pydantic.typing.update_model_forward_refs` * `pydantic.utils.ClassAttribute` * `pydantic.utils.DUNDER_ATTRIBUTES` * `pydantic.utils.PyObjectStr` * `pydantic.utils.ValueItems` * `pydantic.utils.almost_equal_floats` * `pydantic.utils.get_discriminator_alias_and_values` * `pydantic.utils.get_model` * `pydantic.utils.get_unique_discriminator_alias` * `pydantic.utils.in_ipython` * `pydantic.utils.is_valid_identifier` * `pydantic.utils.path_type` * `pydantic.utils.validate_field_name` * `pydantic.validate_model` pydantic-pydantic-ba0aa01/docs/plugins/000077500000000000000000000000001517143232300202175ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/docs/plugins/algolia.py000066400000000000000000000146421517143232300222100ustar00rootroot00000000000000# pyright: reportUnknownMemberType=false # pyright: reportAttributeAccessIssue=false # pyright: reportOptionalMemberAccess=false from __future__ import annotations as _annotations import os import sys from pathlib import Path from typing import TYPE_CHECKING, cast from bs4 import Tag from typing_extensions import TypedDict from pydantic import TypeAdapter if TYPE_CHECKING: from mkdocs.config import Config from mkdocs.structure.files import Files from mkdocs.structure.pages import Page class AlgoliaRecord(TypedDict): content: str pageID: str abs_url: str title: str objectID: str rank: int records: list[AlgoliaRecord] = [] records_ta = TypeAdapter(list[AlgoliaRecord]) # these values should match docs/javascripts/search-worker.js. ALGOLIA_APP_ID = 'KPPUDTIAVX' ALGOLIA_INDEX_NAME = 'pydantic-docs' # Algolia has a limit of 100kb per record in the paid plan, # leave some space for the other fields as well. MAX_CONTENT_LENGTH = 90_000 def get_heading_text(heading: Tag): return heading.get_text().replace('¶', '').strip().replace('\n', ' ') def on_page_content(html: str, page: Page, config: Config, files: Files) -> str: if not os.getenv('CI'): return html from bs4 import BeautifulSoup assert page.title is not None, 'Page title must not be None' title = cast(str, page.title) soup = BeautifulSoup(html, 'html.parser') # If the page does not start with a heading, add the h1 with the title # Some examples don't have a heading. or start with h2 first_element = soup.find() if ( not first_element or not first_element.name # type: ignore[reportAttributeAccessIssue] or first_element.name not in ['h1', 'h2', 'h3'] # type: ignore[reportAttributeAccessIssue] ): soup.insert(0, BeautifulSoup(f'

{title}

', 'html.parser')) # Clean up presentational and UI elements for element in soup.find_all(['autoref']): element.decompose() # this removes the large source code embeds from Github for element in soup.find_all('details'): element.decompose() # Cleanup code examples for extra in soup.find_all('div', attrs={'class': 'language-python highlight'}): extra.replace_with(BeautifulSoup(f'
{extra.find("code").get_text()}
', 'html.parser')) # Cleanup code examples, part 2 for extra in soup.find_all('div', attrs={'class': 'language-python doc-signature highlight'}): extra.replace_with(BeautifulSoup(f'
{extra.find("code").get_text()}
', 'html.parser')) # The API reference generates HTML tables with line numbers, this strips the line numbers cell and goes back to a code block for extra in soup.find_all('table', attrs={'class': 'highlighttable'}): extra.replace_with(BeautifulSoup(f'
{extra.find("code").get_text()}
', 'html.parser')) headings = soup.find_all(['h1', 'h2', 'h3']) # Use the rank to put the sections in the beginning higher in the search results rank = 100 # Process each section for current_heading in headings: heading_id = current_heading.get('id', '') section_title = get_heading_text(current_heading) # type: ignore[reportArgumentType] # Get content until next heading content: list[str] = [] sibling = current_heading.find_next_sibling() while sibling and sibling.name not in {'h1', 'h2', 'h3'}: content.append(str(sibling)) sibling = sibling.find_next_sibling() section_html = ''.join(content) section_soup = BeautifulSoup(section_html, 'html.parser') section_plain_text = section_soup.get_text(' ', strip=True) # Create anchor URL anchor_url: str = f'{page.abs_url}#{heading_id}' if heading_id else page.abs_url or '' record_title = title if current_heading.name == 'h2': record_title = f'{title} - {section_title}' elif current_heading.name == 'h3': previous_heading: Tag = current_heading.find_previous(['h1', 'h2']) # type: ignore[reportAssignmentType] record_title = f'{title} - {get_heading_text(previous_heading)} - {section_title}' # print(f'Adding record {record_title}') # Create record for this section records.append( AlgoliaRecord( content=section_plain_text, pageID=title, abs_url=anchor_url, title=record_title, objectID=anchor_url, rank=rank, ) ) rank -= 5 return html ALGOLIA_RECORDS_FILE = 'algolia_records.json' def on_post_build(config: Config) -> None: if records: algolia_records_path = Path(config['site_dir']) / ALGOLIA_RECORDS_FILE with algolia_records_path.open('wb') as f: f.write(records_ta.dump_json(records)) def algolia_upload() -> None: from algoliasearch.search.client import SearchClientSync algolia_write_api_key = os.environ['ALGOLIA_WRITE_API_KEY'] client = SearchClientSync(ALGOLIA_APP_ID, algolia_write_api_key) filtered_records: list[AlgoliaRecord] = [] algolia_records_path = Path.cwd() / 'site' / ALGOLIA_RECORDS_FILE with algolia_records_path.open('rb') as f: all_records = records_ta.validate_json(f.read()) for record in all_records: content = record['content'] if len(content) > MAX_CONTENT_LENGTH: print( f"Record with title '{record['title']}' has more than {MAX_CONTENT_LENGTH} characters, {len(content)}." ) print(content) else: filtered_records.append(record) print(f'Uploading {len(filtered_records)} out of {len(all_records)} records to Algolia...') client.clear_objects(index_name=ALGOLIA_INDEX_NAME) client.set_settings( index_name=ALGOLIA_INDEX_NAME, index_settings={ 'searchableAttributes': ['title', 'content'], 'attributesToSnippet': ['content:40'], 'customRanking': [ 'desc(rank)', ], }, ) client.batch( index_name=ALGOLIA_INDEX_NAME, batch_write_params={'requests': [{'action': 'addObject', 'body': record} for record in filtered_records]}, ) if __name__ == '__main__': if sys.argv[-1] == 'upload': algolia_upload() else: print('Run with "upload" argument to upload records to Algolia.') sys.exit(1) pydantic-pydantic-ba0aa01/docs/plugins/conversion_table.py000066400000000000000000001154151517143232300241340ustar00rootroot00000000000000from __future__ import annotations as _annotations import collections import typing from collections import deque from collections.abc import Callable, Iterable, Mapping, Sequence from dataclasses import dataclass from datetime import date, datetime, time, timedelta from decimal import Decimal from enum import Enum, IntEnum from ipaddress import IPv4Address, IPv4Interface, IPv4Network, IPv6Address, IPv6Interface, IPv6Network from pathlib import Path from re import Pattern from typing import Any from uuid import UUID from pydantic_core import CoreSchema, core_schema from typing_extensions import TypedDict from pydantic import ByteSize, InstanceOf @dataclass class Row: field_type: type[Any] | str input_type: type[Any] | str python_input: bool = False json_input: bool = False strict: bool = False condition: str | None = None valid_examples: list[Any] | None = None invalid_examples: list[Any] | None = None core_schemas: list[type[CoreSchema]] | None = None @property def field_type_str(self) -> str: return f'{self.field_type.__name__}' if hasattr(self.field_type, '__name__') else f'{self.field_type}' @property def input_type_str(self) -> str: return f'{self.input_type.__name__}' if hasattr(self.input_type, '__name__') else f'{self.input_type}' @property def input_source_str(self) -> str: if self.python_input: if self.json_input: return 'Python & JSON' else: return 'Python' elif self.json_input: return 'JSON' else: return '' @dataclass class ConversionTable: rows: list[Row] col_names = [ 'Field Type', 'Input', 'Strict', 'Input Source', 'Conditions', ] open_nowrap_span = '' close_nowrap_span = '' def col_values(self, row: Row) -> list[str]: o = self.open_nowrap_span c = self.close_nowrap_span return [ f'{o}`{row.field_type_str}`{c}', f'{o}`{row.input_type_str}`{c}', '✓' if row.strict else '', f'{o}{row.input_source_str}{c}', row.condition if row.condition else '', ] @staticmethod def row_as_markdown(cols: list[str]) -> str: return f'| {" | ".join(cols)} |' def as_markdown(self) -> str: lines = [self.row_as_markdown(self.col_names), self.row_as_markdown(['-'] * len(self.col_names))] + [ self.row_as_markdown(self.col_values(row)) for row in self.rows ] return '\n'.join(lines) @staticmethod def row_sort_key(row: Row) -> Any: field_type = row.field_type_str or ' ' input_type = row.input_type_str or ' ' input_source = row.input_source_str # Include the .isupper() to make it so that leading-lowercase items come first return field_type[0].isupper(), field_type, input_type[0].isupper(), input_type, input_source def sorted(self) -> ConversionTable: return ConversionTable(sorted(self.rows, key=self.row_sort_key)) def filtered(self, predicate: Callable[[Row], bool]) -> ConversionTable: return ConversionTable([row for row in self.rows if predicate(row)]) table_rows: list[Row] = [ Row( str, str, strict=True, python_input=True, json_input=True, core_schemas=[core_schema.StringSchema], ), Row( str, bytes, python_input=True, condition='Assumes UTF-8, error on unicode decoding error.', valid_examples=[b'this is bytes'], invalid_examples=[b'\x81'], core_schemas=[core_schema.StringSchema], ), Row( str, bytearray, python_input=True, condition='Assumes UTF-8, error on unicode decoding error.', valid_examples=[bytearray(b'this is bytearray' * 3)], invalid_examples=[bytearray(b'\x81' * 5)], core_schemas=[core_schema.StringSchema], ), Row( bytes, bytes, strict=True, python_input=True, core_schemas=[core_schema.BytesSchema], ), Row( bytes, str, strict=True, json_input=True, valid_examples=['foo'], core_schemas=[core_schema.BytesSchema], ), Row( bytes, str, python_input=True, valid_examples=['foo'], core_schemas=[core_schema.BytesSchema], ), Row( bytes, bytearray, python_input=True, valid_examples=[bytearray(b'this is bytearray' * 3)], core_schemas=[core_schema.BytesSchema], ), Row( int, int, strict=True, python_input=True, json_input=True, condition='`bool` is explicitly forbidden.', invalid_examples=[2**64, True, False], core_schemas=[core_schema.IntSchema], ), Row( int, int, python_input=True, json_input=True, core_schemas=[core_schema.IntSchema], ), Row( int, float, python_input=True, json_input=True, condition='Must be exact int, e.g. `val % 1 == 0`, raises error for `nan`, `inf`.', valid_examples=[2.0], invalid_examples=[2.1, 2.2250738585072011e308, float('nan'), float('inf')], core_schemas=[core_schema.IntSchema], ), Row( int, Decimal, python_input=True, condition='Must be exact int, e.g. `val % 1 == 0`.', valid_examples=[Decimal(2.0)], invalid_examples=[Decimal(2.1)], core_schemas=[core_schema.IntSchema], ), Row( int, bool, python_input=True, json_input=True, valid_examples=[True, False], core_schemas=[core_schema.IntSchema], ), Row( int, str, python_input=True, json_input=True, condition='Must be numeric only, e.g. `[0-9]+`.', valid_examples=['123'], invalid_examples=['test', '123x'], core_schemas=[core_schema.IntSchema], ), Row( int, bytes, python_input=True, condition='Must be numeric only, e.g. `[0-9]+`.', valid_examples=[b'123'], invalid_examples=[b'test', b'123x'], core_schemas=[core_schema.IntSchema], ), Row( float, float, strict=True, python_input=True, json_input=True, condition='`bool` is explicitly forbidden.', invalid_examples=[True, False], core_schemas=[core_schema.FloatSchema], ), Row( float, int, strict=True, python_input=True, json_input=True, valid_examples=[123], core_schemas=[core_schema.FloatSchema], ), Row( float, str, python_input=True, json_input=True, condition='Must match `[0-9]+(\\.[0-9]+)?`.', valid_examples=['3.141'], invalid_examples=['test', '3.141x'], core_schemas=[core_schema.FloatSchema], ), Row( float, bytes, python_input=True, condition='Must match `[0-9]+(\\.[0-9]+)?`.', valid_examples=[b'3.141'], invalid_examples=[b'test', b'3.141x'], core_schemas=[core_schema.FloatSchema], ), Row( float, Decimal, python_input=True, valid_examples=[Decimal(3.5)], core_schemas=[core_schema.FloatSchema], ), Row( float, bool, python_input=True, json_input=True, valid_examples=[True, False], core_schemas=[core_schema.FloatSchema], ), Row( bool, bool, strict=True, python_input=True, json_input=True, valid_examples=[True, False], core_schemas=[core_schema.BoolSchema], ), Row( bool, int, python_input=True, json_input=True, condition='Allowed values: `0, 1`.', valid_examples=[0, 1], invalid_examples=[2, 100], core_schemas=[core_schema.BoolSchema], ), Row( bool, float, python_input=True, json_input=True, condition='Allowed values: `0.0, 1.0`.', valid_examples=[0.0, 1.0], invalid_examples=[2.0, 100.0], core_schemas=[core_schema.BoolSchema], ), Row( bool, Decimal, python_input=True, condition='Allowed values: `Decimal(0), Decimal(1)`.', valid_examples=[Decimal(0), Decimal(1)], invalid_examples=[Decimal(2), Decimal(100)], core_schemas=[core_schema.BoolSchema], ), Row( bool, str, python_input=True, json_input=True, condition=( "Allowed values: `'f'`, `'n'`, `'no'`, `'off'`, `'false'`, `'False'`, `'t'`, `'y'`, " "`'on'`, `'yes'`, `'true'`, `'True'`." ), valid_examples=['f', 'n', 'no', 'off', 'false', 'False', 't', 'y', 'on', 'yes', 'true', 'True'], invalid_examples=['test'], core_schemas=[core_schema.BoolSchema], ), Row( None, None, strict=True, python_input=True, json_input=True, core_schemas=[core_schema.NoneSchema], ), Row( date, date, strict=True, python_input=True, core_schemas=[core_schema.DateSchema], ), Row( date, datetime, python_input=True, condition='Must be exact date, eg. no `H`, `M`, `S`, `f`.', valid_examples=[datetime(2017, 5, 5)], invalid_examples=[datetime(2017, 5, 5, 10)], core_schemas=[core_schema.DateSchema], ), Row( date, str, python_input=True, json_input=True, condition='Format: `YYYY-MM-DD`.', valid_examples=['2017-05-05'], invalid_examples=['2017-5-5', '2017/05/05'], core_schemas=[core_schema.DateSchema], ), Row( date, bytes, python_input=True, condition='Format: `YYYY-MM-DD` (UTF-8).', valid_examples=[b'2017-05-05'], invalid_examples=[b'2017-5-5', b'2017/05/05'], core_schemas=[core_schema.DateSchema], ), Row( date, int, python_input=True, json_input=True, condition=( 'Interpreted as seconds or ms from epoch. ' 'See [speedate](https://docs.rs/speedate/latest/speedate/). Must be exact date.' ), valid_examples=[1493942400000, 1493942400], invalid_examples=[1493942401000], core_schemas=[core_schema.DateSchema], ), Row( date, float, python_input=True, json_input=True, condition=( 'Interpreted as seconds or ms from epoch. ' 'See [speedate](https://docs.rs/speedate/latest/speedate/). Must be exact date.' ), valid_examples=[1493942400000.0, 1493942400.0], invalid_examples=[1493942401000.0], core_schemas=[core_schema.DateSchema], ), Row( date, Decimal, python_input=True, condition=( 'Interpreted as seconds or ms from epoch. ' 'See [speedate](https://docs.rs/speedate/latest/speedate/). Must be exact date.' ), valid_examples=[Decimal(1493942400000), Decimal(1493942400)], invalid_examples=[Decimal(1493942401000)], core_schemas=[core_schema.DateSchema], ), Row( datetime, datetime, strict=True, python_input=True, core_schemas=[core_schema.DatetimeSchema], ), Row( datetime, date, python_input=True, valid_examples=[date(2017, 5, 5)], core_schemas=[core_schema.DatetimeSchema], ), Row( datetime, str, python_input=True, json_input=True, condition='Format: `YYYY-MM-DDTHH:MM:SS.f` or `YYYY-MM-DD`. See [speedate](https://docs.rs/speedate/latest/speedate/).', valid_examples=['2017-05-05 10:10:10', '2017-05-05T10:10:10.0002', '2017-05-05 10:10:10+00:00', '2017-05-05'], invalid_examples=['2017-5-5T10:10:10'], core_schemas=[core_schema.DatetimeSchema], ), Row( datetime, bytes, python_input=True, condition=( 'Format: `YYYY-MM-DDTHH:MM:SS.f` or `YYYY-MM-DD`. See [speedate](https://docs.rs/speedate/latest/speedate/), (UTF-8).' ), valid_examples=[b'2017-05-05 10:10:10', b'2017-05-05T10:10:10.0002', b'2017-05-05 10:10:10+00:00'], invalid_examples=[b'2017-5-5T10:10:10'], core_schemas=[core_schema.DatetimeSchema], ), Row( datetime, int, python_input=True, json_input=True, condition='Interpreted as seconds or ms from epoch, see [speedate](https://docs.rs/speedate/latest/speedate/).', valid_examples=[1493979010000, 1493979010], core_schemas=[core_schema.DatetimeSchema], ), Row( datetime, float, python_input=True, json_input=True, condition='Interpreted as seconds or ms from epoch, see [speedate](https://docs.rs/speedate/latest/speedate/).', valid_examples=[1493979010000.0, 1493979010.0], core_schemas=[core_schema.DatetimeSchema], ), Row( datetime, Decimal, python_input=True, condition='Interpreted as seconds or ms from epoch, see [speedate](https://docs.rs/speedate/latest/speedate/).', valid_examples=[Decimal(1493979010000), Decimal(1493979010)], core_schemas=[core_schema.DatetimeSchema], ), Row( time, time, strict=True, python_input=True, core_schemas=[core_schema.TimeSchema], ), Row( time, str, python_input=True, json_input=True, condition='Format: `HH:MM:SS.FFFFFF`. See [speedate](https://docs.rs/speedate/latest/speedate/).', valid_examples=['10:10:10.0002'], invalid_examples=['1:1:1'], core_schemas=[core_schema.TimeSchema], ), Row( time, bytes, python_input=True, condition='Format: `HH:MM:SS.FFFFFF`. See [speedate](https://docs.rs/speedate/latest/speedate/).', valid_examples=[b'10:10:10.0002'], invalid_examples=[b'1:1:1'], core_schemas=[core_schema.TimeSchema], ), Row( time, int, python_input=True, json_input=True, condition='Interpreted as seconds, range `0 - 86399`.', valid_examples=[3720], invalid_examples=[-1, 86400], core_schemas=[core_schema.TimeSchema], ), Row( time, float, python_input=True, json_input=True, condition='Interpreted as seconds, range `0 - 86399.9*`.', valid_examples=[3720.0002], invalid_examples=[-1.0, 86400.0], core_schemas=[core_schema.TimeSchema], ), Row( time, Decimal, python_input=True, condition='Interpreted as seconds, range `0 - 86399.9*`.', valid_examples=[Decimal(3720.0002)], invalid_examples=[Decimal(-1), Decimal(86400)], core_schemas=[core_schema.TimeSchema], ), Row( timedelta, timedelta, strict=True, python_input=True, core_schemas=[core_schema.TimedeltaSchema], ), Row( timedelta, str, python_input=True, json_input=True, condition='Format: `ISO8601`. See [speedate](https://docs.rs/speedate/latest/speedate/).', valid_examples=['1 days 10:10', '1 d 10:10'], invalid_examples=['1 10:10'], core_schemas=[core_schema.TimedeltaSchema], ), Row( timedelta, bytes, python_input=True, condition='Format: `ISO8601`. See [speedate](https://docs.rs/speedate/latest/speedate/), (UTF-8).', valid_examples=[b'1 days 10:10', b'1 d 10:10'], invalid_examples=[b'1 10:10'], core_schemas=[core_schema.TimedeltaSchema], ), Row( timedelta, int, python_input=True, json_input=True, condition='Interpreted as seconds.', valid_examples=[123_000], core_schemas=[core_schema.TimedeltaSchema], ), Row( timedelta, float, python_input=True, json_input=True, condition='Interpreted as seconds.', valid_examples=[123_000.0002], core_schemas=[core_schema.TimedeltaSchema], ), Row( timedelta, Decimal, python_input=True, condition='Interpreted as seconds.', valid_examples=[Decimal(123_000.0002)], core_schemas=[core_schema.TimedeltaSchema], ), Row( dict, dict, strict=True, python_input=True, core_schemas=[core_schema.DictSchema], ), Row( dict, 'Object', strict=True, json_input=True, valid_examples=['{"v": {"1": 1, "2": 2}}'], core_schemas=[core_schema.DictSchema], ), Row( dict, Mapping, python_input=True, condition='Must implement the mapping interface and have an `items()` method.', valid_examples=[], core_schemas=[core_schema.DictSchema], ), Row( TypedDict, dict, strict=True, python_input=True, core_schemas=[core_schema.TypedDictSchema], ), Row( TypedDict, 'Object', strict=True, json_input=True, core_schemas=[core_schema.TypedDictSchema], ), Row( TypedDict, Any, strict=True, python_input=True, core_schemas=[core_schema.TypedDictSchema], ), Row( TypedDict, Mapping, python_input=True, condition='Must implement the mapping interface and have an `items()` method.', valid_examples=[], core_schemas=[core_schema.TypedDictSchema], ), Row( list, list, strict=True, python_input=True, core_schemas=[core_schema.ListSchema], ), Row( list, 'Array', strict=True, json_input=True, core_schemas=[core_schema.ListSchema], ), Row( list, tuple, python_input=True, core_schemas=[core_schema.ListSchema], ), Row( list, set, python_input=True, core_schemas=[core_schema.ListSchema], ), Row( list, frozenset, python_input=True, core_schemas=[core_schema.ListSchema], ), Row( list, deque, python_input=True, core_schemas=[core_schema.ListSchema], ), Row( list, 'dict_keys', python_input=True, core_schemas=[core_schema.ListSchema], ), Row( list, 'dict_values', python_input=True, core_schemas=[core_schema.ListSchema], ), Row( tuple, tuple, strict=True, python_input=True, core_schemas=[core_schema.TupleSchema], ), Row( tuple, 'Array', strict=True, json_input=True, core_schemas=[core_schema.TupleSchema], ), Row( tuple, list, python_input=True, core_schemas=[core_schema.TupleSchema], ), Row( tuple, set, python_input=True, core_schemas=[core_schema.TupleSchema], ), Row( tuple, frozenset, python_input=True, core_schemas=[core_schema.TupleSchema], ), Row( tuple, deque, python_input=True, core_schemas=[core_schema.TupleSchema], ), Row( tuple, 'dict_keys', python_input=True, core_schemas=[core_schema.TupleSchema], ), Row( tuple, 'dict_values', python_input=True, core_schemas=[core_schema.TupleSchema], ), Row( set, set, strict=True, python_input=True, core_schemas=[core_schema.SetSchema], ), Row( set, 'Array', strict=True, json_input=True, core_schemas=[core_schema.SetSchema], ), Row( set, list, python_input=True, core_schemas=[core_schema.SetSchema], ), Row( set, tuple, python_input=True, core_schemas=[core_schema.SetSchema], ), Row( set, frozenset, python_input=True, core_schemas=[core_schema.SetSchema], ), Row( set, deque, python_input=True, core_schemas=[core_schema.SetSchema], ), Row( set, 'dict_keys', python_input=True, core_schemas=[core_schema.SetSchema], ), Row( set, 'dict_values', python_input=True, core_schemas=[core_schema.SetSchema], ), Row( frozenset, frozenset, strict=True, python_input=True, core_schemas=[core_schema.FrozenSetSchema], ), Row( frozenset, 'Array', strict=True, json_input=True, core_schemas=[core_schema.FrozenSetSchema], ), Row( frozenset, list, python_input=True, core_schemas=[core_schema.FrozenSetSchema], ), Row( frozenset, tuple, python_input=True, core_schemas=[core_schema.FrozenSetSchema], ), Row( frozenset, set, python_input=True, core_schemas=[core_schema.FrozenSetSchema], ), Row( frozenset, deque, python_input=True, core_schemas=[core_schema.FrozenSetSchema], ), Row( frozenset, 'dict_keys', python_input=True, core_schemas=[core_schema.FrozenSetSchema], ), Row( frozenset, 'dict_values', python_input=True, core_schemas=[core_schema.FrozenSetSchema], ), Row( InstanceOf, Any, strict=True, python_input=True, condition='`isinstance()` check must return `True`.', core_schemas=[core_schema.IsInstanceSchema], ), Row( InstanceOf, '-', json_input=True, condition='Never valid.', core_schemas=[core_schema.IsInstanceSchema], ), Row( callable, Any, strict=True, python_input=True, condition='`callable()` check must return `True`.', core_schemas=[core_schema.CallableSchema], ), Row( callable, '-', json_input=True, condition='Never valid.', core_schemas=[core_schema.CallableSchema], ), Row( deque, deque, strict=True, python_input=True, core_schemas=[core_schema.WrapValidatorFunctionSchema], ), Row( deque, 'Array', strict=True, json_input=True, core_schemas=[core_schema.WrapValidatorFunctionSchema], ), Row( deque, list, python_input=True, core_schemas=[core_schema.ChainSchema], ), Row( deque, tuple, python_input=True, core_schemas=[core_schema.ChainSchema], ), Row( deque, set, python_input=True, core_schemas=[core_schema.ChainSchema], ), Row( deque, frozenset, python_input=True, core_schemas=[core_schema.ChainSchema], ), Row( Any, Any, strict=True, python_input=True, json_input=True, core_schemas=[core_schema.AnySchema], ), Row( typing.NamedTuple, typing.NamedTuple, strict=True, python_input=True, core_schemas=[core_schema.CallSchema], ), Row( typing.NamedTuple, 'Array', strict=True, json_input=True, core_schemas=[core_schema.CallSchema], ), Row( typing.NamedTuple, collections.namedtuple, strict=True, python_input=True, core_schemas=[core_schema.CallSchema], ), Row( typing.NamedTuple, tuple, strict=True, python_input=True, core_schemas=[core_schema.CallSchema], ), Row( typing.NamedTuple, list, strict=True, python_input=True, core_schemas=[core_schema.CallSchema], ), Row( typing.NamedTuple, dict, strict=True, python_input=True, core_schemas=[core_schema.CallSchema], ), Row( collections.namedtuple, collections.namedtuple, strict=True, python_input=True, core_schemas=[core_schema.CallSchema], ), Row( collections.namedtuple, 'Array', strict=True, json_input=True, core_schemas=[core_schema.CallSchema], ), Row( collections.namedtuple, typing.NamedTuple, strict=True, python_input=True, core_schemas=[core_schema.CallSchema], ), Row( collections.namedtuple, tuple, strict=True, python_input=True, core_schemas=[core_schema.CallSchema], ), Row( collections.namedtuple, list, strict=True, python_input=True, core_schemas=[core_schema.CallSchema], ), Row( collections.namedtuple, dict, strict=True, python_input=True, core_schemas=[core_schema.CallSchema], ), Row( Sequence, list, strict=True, python_input=True, core_schemas=[core_schema.ChainSchema], ), Row( Sequence, 'Array', strict=True, json_input=True, core_schemas=[core_schema.ChainSchema], ), Row( Sequence, tuple, python_input=True, core_schemas=[core_schema.ChainSchema], ), Row( Sequence, deque, python_input=True, core_schemas=[core_schema.ChainSchema], ), Row( Iterable, list, strict=True, python_input=True, core_schemas=[core_schema.GeneratorSchema], ), Row( Iterable, 'Array', strict=True, json_input=True, core_schemas=[core_schema.GeneratorSchema], ), Row( Iterable, tuple, strict=True, python_input=True, core_schemas=[core_schema.GeneratorSchema], ), Row( Iterable, set, strict=True, python_input=True, core_schemas=[core_schema.GeneratorSchema], ), Row( Iterable, frozenset, strict=True, python_input=True, core_schemas=[core_schema.GeneratorSchema], ), Row( Iterable, deque, strict=True, python_input=True, core_schemas=[core_schema.GeneratorSchema], ), Row( type, type, strict=True, python_input=True, core_schemas=[core_schema.IsSubclassSchema], ), Row( Pattern, str, strict=True, python_input=True, json_input=True, condition='Input must be a valid pattern.', core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( Pattern, bytes, strict=True, python_input=True, condition='Input must be a valid pattern.', core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IPv4Address, IPv4Address, strict=True, python_input=True, core_schemas=[core_schema.IsInstanceSchema], ), Row( IPv4Address, IPv4Interface, strict=True, python_input=True, core_schemas=[core_schema.IsInstanceSchema], ), Row( IPv4Address, str, strict=True, json_input=True, core_schemas=[core_schema.AfterValidatorFunctionSchema], ), Row( IPv4Address, str, python_input=True, json_input=True, core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IPv4Address, bytes, python_input=True, valid_examples=[b'\x00\x00\x00\x00'], core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IPv4Address, int, python_input=True, condition='integer representing the IP address, must be less than `2**32`', valid_examples=[168_430_090], core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IPv4Interface, IPv4Interface, strict=True, python_input=True, core_schemas=[core_schema.IsInstanceSchema], ), Row( IPv4Interface, str, strict=True, json_input=True, core_schemas=[core_schema.AfterValidatorFunctionSchema], ), Row( IPv4Interface, IPv4Address, python_input=True, core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IPv4Interface, str, python_input=True, json_input=True, core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IPv4Interface, bytes, python_input=True, valid_examples=[b'\xff\xff\xff\xff'], core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IPv4Interface, tuple, python_input=True, valid_examples=[('192.168.0.1', '24')], core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IPv4Interface, int, python_input=True, condition='integer representing the IP address, must be less than `2**32`', valid_examples=[168_430_090], core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IPv4Network, IPv4Network, strict=True, python_input=True, core_schemas=[core_schema.IsInstanceSchema], ), Row( IPv4Network, str, strict=True, json_input=True, core_schemas=[core_schema.AfterValidatorFunctionSchema], ), Row( IPv4Network, IPv4Address, python_input=True, core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IPv4Network, IPv4Interface, python_input=True, core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IPv4Network, str, python_input=True, json_input=True, core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IPv4Network, bytes, python_input=True, valid_examples=[b'\xff\xff\xff\xff'], core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IPv4Network, int, python_input=True, condition='integer representing the IP network, must be less than `2**32`', valid_examples=[168_430_090], core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IPv6Address, IPv6Address, strict=True, python_input=True, core_schemas=[core_schema.IsInstanceSchema], ), Row( IPv6Address, IPv6Interface, strict=True, python_input=True, core_schemas=[core_schema.IsInstanceSchema], ), Row( IPv6Address, str, strict=True, json_input=True, core_schemas=[core_schema.AfterValidatorFunctionSchema], ), Row( IPv6Address, str, python_input=True, json_input=True, core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IPv6Address, bytes, python_input=True, valid_examples=[b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01'], core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IPv6Address, int, python_input=True, condition='integer representing the IP address, must be less than `2**128`', valid_examples=[340_282_366_920_938_463_463_374_607_431_768_211_455], core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IPv6Interface, IPv6Interface, strict=True, python_input=True, core_schemas=[core_schema.IsInstanceSchema], ), Row( IPv6Interface, str, strict=True, json_input=True, core_schemas=[core_schema.AfterValidatorFunctionSchema], ), Row( IPv6Interface, IPv6Address, python_input=True, core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IPv6Interface, str, python_input=True, json_input=True, core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IPv6Interface, bytes, python_input=True, valid_examples=[b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01'], core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IPv6Interface, tuple, python_input=True, valid_examples=[('2001:db00::1', '120')], core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IPv6Interface, int, python_input=True, condition='integer representing the IP address, must be less than `2**128`', valid_examples=[340_282_366_920_938_463_463_374_607_431_768_211_455], core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IPv6Network, IPv6Network, strict=True, python_input=True, core_schemas=[core_schema.IsInstanceSchema], ), Row( IPv6Network, str, strict=True, json_input=True, core_schemas=[core_schema.AfterValidatorFunctionSchema], ), Row( IPv6Network, IPv6Address, python_input=True, core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IPv6Network, IPv6Interface, python_input=True, core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IPv6Network, str, python_input=True, json_input=True, core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IPv6Network, bytes, python_input=True, valid_examples=[b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01'], core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IPv6Network, int, python_input=True, condition='integer representing the IP address, must be less than `2**128`', valid_examples=[340_282_366_920_938_463_463_374_607_431_768_211_455], core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( Enum, Enum, strict=True, python_input=True, core_schemas=[core_schema.IsInstanceSchema], ), Row( Enum, Any, strict=True, json_input=True, condition='Input value must be convertible to enum values.', core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( Enum, Any, python_input=True, condition='Input value must be convertible to enum values.', core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IntEnum, IntEnum, strict=True, python_input=True, core_schemas=[core_schema.IsInstanceSchema], ), Row( IntEnum, Any, strict=True, json_input=True, condition='Input value must be convertible to enum values.', core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( IntEnum, Any, python_input=True, condition='Input value must be convertible to enum values.', core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( Decimal, Decimal, strict=True, python_input=True, core_schemas=[core_schema.CustomErrorSchema], ), Row( Decimal, int, strict=True, json_input=True, core_schemas=[core_schema.CustomErrorSchema], ), Row( Decimal, str, strict=True, json_input=True, core_schemas=[core_schema.CustomErrorSchema], ), Row( Decimal, float, strict=True, json_input=True, core_schemas=[core_schema.CustomErrorSchema], ), Row( Decimal, int, python_input=True, json_input=True, core_schemas=[core_schema.AfterValidatorFunctionSchema], ), Row( Decimal, str, python_input=True, json_input=True, condition='Must match `[0-9]+(\\.[0-9]+)?`.', valid_examples=['3.141'], invalid_examples=['test', '3.141x'], core_schemas=[core_schema.AfterValidatorFunctionSchema], ), Row( Decimal, float, python_input=True, json_input=True, core_schemas=[core_schema.AfterValidatorFunctionSchema], ), Row( Path, Path, strict=True, python_input=True, core_schemas=[core_schema.IsInstanceSchema], ), Row( Path, str, strict=True, json_input=True, core_schemas=[core_schema.AfterValidatorFunctionSchema], ), Row( Path, str, python_input=True, core_schemas=[core_schema.AfterValidatorFunctionSchema], ), Row( UUID, UUID, strict=True, python_input=True, core_schemas=[core_schema.IsInstanceSchema], ), Row( UUID, str, strict=True, json_input=True, core_schemas=[core_schema.AfterValidatorFunctionSchema], ), Row( UUID, str, python_input=True, valid_examples=['{12345678-1234-5678-1234-567812345678}'], core_schemas=[core_schema.AfterValidatorFunctionSchema], ), Row( ByteSize, str, strict=True, python_input=True, json_input=True, valid_examples=['1.2', '1.5 KB', '6.2EiB'], core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( ByteSize, int, strict=True, python_input=True, json_input=True, core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( ByteSize, float, strict=True, python_input=True, json_input=True, core_schemas=[core_schema.PlainValidatorFunctionSchema], ), Row( ByteSize, Decimal, strict=True, python_input=True, core_schemas=[core_schema.PlainValidatorFunctionSchema], ), ] conversion_table = ConversionTable(table_rows).sorted() pydantic-pydantic-ba0aa01/docs/plugins/devtools_output.html000066400000000000000000000067251517143232300243760ustar00rootroot00000000000000 devtools_example.py:30 <module> user: User( id=123, name='John Doe', signup_ts=datetime.datetime(2019, 6, 1, 12, 22), friends=[ 1234, 4567, 7890, ], address=Address( street='Testing', country='uk', lat=51.5, lng=0.0, ), ) (User) should be much easier read than: user: id=123 name='John Doe' signup_ts=datetime.datetime(2019, 6, 1, 12, 22) friends=[1234, 4567, 7890] address=Address(street='Testing', country='uk', lat=51.5, lng=0.0) pydantic-pydantic-ba0aa01/docs/plugins/main.py000066400000000000000000000372241517143232300215250ustar00rootroot00000000000000from __future__ import annotations as _annotations import json import logging import os import re import textwrap from pathlib import Path from textwrap import indent import autoflake import pyupgrade._main as pyupgrade_main # type: ignore import requests import tomli import yaml from build.__main__ import ( build_package, ) # Might be private, but there's currently no public API to programmatically build wheels.. from jinja2 import Template # type: ignore from mkdocs.config.defaults import MkDocsConfig from mkdocs.exceptions import PluginError from mkdocs.structure.files import Files from mkdocs.structure.pages import Page from packaging.version import Version logger = logging.getLogger('mkdocs.plugin') THIS_DIR = Path(__file__).parent DOCS_DIR = THIS_DIR.parent PROJECT_ROOT = DOCS_DIR.parent try: from .conversion_table import conversion_table except ImportError: # Due to how MkDocs requires this file to be specified (as a path and not a # dot-separated module name), relative imports don't work: # MkDocs is adding the dir. of this file to `sys.path` and uses # `importlib.spec_from_file_location` and `module_from_spec`, which isn't ideal. from conversion_table import conversion_table # Start definition of MkDocs hooks def on_pre_build(config: MkDocsConfig) -> None: """ Before the build starts. """ add_changelog() if not config.site_url: raise PluginError("'site_url' must be set") add_mkdocs_run_deps(config.site_url) def on_page_markdown(markdown: str, page: Page, config: MkDocsConfig, files: Files) -> str: """ Called on each file after it is read and before it is converted to HTML. """ markdown = upgrade_python(markdown) markdown = insert_json_output(markdown) if md := render_index(markdown, page): return md if md := render_why(markdown, page): return md if md := render_pydantic_settings(markdown, page): return md elif md := build_schema_mappings(markdown, page): return md elif md := build_conversion_table(markdown, page): return md elif md := devtools_example(markdown, page): return md elif md := populate_pydantic_people(markdown, page): return md else: return markdown # End definition of MkDocs hooks def add_changelog() -> None: history = (PROJECT_ROOT / 'HISTORY.md').read_text(encoding='utf-8') history = re.sub(r'(\s)@([\w\-]+)', r'\1[@\2](https://github.com/\2)', history, flags=re.I) history = re.sub(r'\[GitHub release]\(', r'[:simple-github: GitHub release](', history) history = re.sub('@@', '@', history) new_file = DOCS_DIR / 'changelog.md' # avoid writing file unless the content has changed to avoid infinite build loop if not new_file.is_file() or new_file.read_text(encoding='utf-8') != history: new_file.write_text(history, encoding='utf-8') def add_mkdocs_run_deps(site_url: str) -> None: # set the pydantic, pydantic-core, pydantic-extra-types versions to configure for running examples in the browser pyproject_toml = (PROJECT_ROOT / 'pyproject.toml').read_text() m = re.search(r'pydantic-core==(.+?)["\']', pyproject_toml) if not m: logger.info( "Could not find pydantic-core version in pyproject.toml, this is expected if you're using a git ref" ) return pydantic_core_version = m.group(1) version_py = (PROJECT_ROOT / 'pydantic' / 'version.py').read_text() pydantic_version_str: str = re.search(r'^VERSION ?= (["\'])(.+)\1', version_py, flags=re.M).group(2) # pyright: ignore[reportOptionalMemberAccess] if os.getenv('CI') and Version(pydantic_version_str).local == 'dev': build_package( PROJECT_ROOT, DOCS_DIR, distributions=['wheel'], ) wheel_file = next(DOCS_DIR.glob('*.whl')) pydantic_dep = f'{site_url.removesuffix("/").removesuffix("/latest")}/dev/{wheel_file.name}' else: pydantic_dep = f'pydantic=={pydantic_version_str}' uv_lock = (PROJECT_ROOT / 'uv.lock').read_text() pydantic_extra_types_version: str = re.search(r'name = "pydantic-extra-types"\nversion = "(.+?)"', uv_lock).group(1) # pyright: ignore[reportOptionalMemberAccess] mkdocs_run_deps = json.dumps( [ pydantic_dep, 'email-validator>=2.0.0', f'pydantic-core=={pydantic_core_version}', f'pydantic-extra-types=={pydantic_extra_types_version}', ] ) logger.info('Setting mkdocs_run_deps=%s', mkdocs_run_deps) html = f"""\ """ path = DOCS_DIR / 'theme/mkdocs_run_deps.html' path.write_text(html) MIN_MINOR_VERSION = 9 MAX_MINOR_VERSION = 13 def upgrade_python(markdown: str) -> str: """ Apply pyupgrade to all Python code blocks, unless explicitly skipped, create a tab for each version. """ def add_tabs(match: re.Match[str]) -> str: prefix = match.group(1) if 'upgrade="skip"' in prefix: return match.group(0) if m := re.search(r'requires="3.(\d+)"', prefix): min_minor_version = int(m.group(1)) else: min_minor_version = MIN_MINOR_VERSION py_code = match.group(2) numbers = match.group(3) # import devtools # devtools.debug(numbers) output = [] last_code = py_code for minor_version in range(min_minor_version, MAX_MINOR_VERSION + 1): if minor_version == min_minor_version: tab_code = py_code else: tab_code = _upgrade_code(py_code, minor_version) if tab_code == last_code: continue last_code = tab_code content = indent(f'{prefix}\n{tab_code}```{numbers}', ' ' * 4) output.append(f'=== "Python 3.{minor_version} and above"\n\n{content}') if len(output) == 1: return match.group(0) else: return '\n\n'.join(output) # Note: we should move away from this regex approach. It does not handle edge cases (indented code blocks inside # other blocks, etc) and can lead to bugs in the rendering of annotations. Edit with care and make sure the rendered # documentation does not break: return re.sub(r'(``` *py.*?)\n(.+?)^```(\s+(?:^\d+\. (?:[^\n][\n]?)+\n?)*)', add_tabs, markdown, flags=re.M | re.S) def _upgrade_code(code: str, min_version: int) -> str: upgraded = pyupgrade_main._fix_plugins( code, settings=pyupgrade_main.Settings( min_version=(3, min_version), keep_percent_format=True, keep_mock=False, keep_runtime_typing=True, ), ) return autoflake.fix_code(upgraded, remove_all_unused_imports=True) def insert_json_output(markdown: str) -> str: """ Find `output="json"` code fence tags and replace with a separate JSON section """ def replace_json(m: re.Match[str]) -> str: start, attrs, code = m.groups() def replace_last_print(m2: re.Match[str]) -> str: ind, json_text = m2.groups() json_text = indent(json.dumps(json.loads(json_text), indent=2), ind) # no trailing fence as that's not part of code return f'\n{ind}```\n\n{ind}JSON output:\n\n{ind}```json\n{json_text}\n' code = re.sub(r'\n( *)"""(.*?)\1"""\n$', replace_last_print, code, flags=re.S) return f'{start}{attrs}{code}{start}\n' return re.sub(r'(^ *```)([^\n]*?output="json"[^\n]*?\n)(.+?)\1', replace_json, markdown, flags=re.M | re.S) def get_orgs_data() -> list[dict[str, str]]: with (THIS_DIR / 'orgs.toml').open('rb') as f: orgs_data = tomli.load(f) return orgs_data['orgs'] tile_template = """ """ def render_index(markdown: str, page: Page) -> str | None: if page.file.src_uri != 'index.md': return None if version := os.getenv('PYDANTIC_VERSION'): url = f'https://github.com/pydantic/pydantic/releases/tag/{version}' version_str = f'Documentation for version: [{version}]({url})' elif (version_ref := os.getenv('GITHUB_REF')) and version_ref.startswith('refs/tags/'): version = re.sub('^refs/tags/', '', version_ref.lower()) url = f'https://github.com/pydantic/pydantic/releases/tag/{version}' version_str = f'Documentation for version: [{version}]({url})' elif sha := os.getenv('GITHUB_SHA'): url = f'https://github.com/pydantic/pydantic/commit/{sha}' sha = sha[:7] version_str = f'Documentation for development version: [{sha}]({url})' else: version_str = 'Documentation for development version' logger.info('Setting version prefix: %r', version_str) markdown = re.sub(r'{{ *version *}}', version_str, markdown) elements = [tile_template.format(**org) for org in get_orgs_data()] orgs_grid = f'
{"".join(elements)}
' return re.sub(r'{{ *organisations *}}', orgs_grid, markdown) def render_why(markdown: str, page: Page) -> str | None: if page.file.src_uri != 'why.md': return None with (THIS_DIR / 'using.toml').open('rb') as f: using = tomli.load(f)['libs'] libraries = '\n'.join('* [`{repo}`](https://github.com/{repo}) {stars:,} stars'.format(**lib) for lib in using) markdown = re.sub(r'{{ *libraries *}}', libraries, markdown) default_description = '_(Based on the criteria described above)_' elements = [ f'### {org["name"]} {{#org-{org["key"]}}}\n\n{org.get("description") or default_description}' for org in get_orgs_data() ] return re.sub(r'{{ *organisations *}}', '\n\n'.join(elements), markdown) def render_pydantic_settings(markdown: str, page: Page) -> str | None: if page.file.src_uri != 'concepts/pydantic_settings.md': return None req = requests.get('https://raw.githubusercontent.com/pydantic/pydantic-settings/main/docs/index.md') if req.status_code != 200: logger.warning( 'Got HTTP status %d when trying to fetch content of the `pydantic-settings` docs', req.status_code ) return docs_content = req.text.strip() return re.sub(r'{{ *pydantic_settings *}}', docs_content, markdown) def _generate_table_row(col_values: list[str]) -> str: return f'| {" | ".join(col_values)} |\n' def _generate_table_heading(col_names: list[str]) -> str: return _generate_table_row(col_names) + _generate_table_row(['-'] * len(col_names)) def build_schema_mappings(markdown: str, page: Page) -> str | None: if page.file.src_uri != 'concepts/json_schema.md': return None col_names = [ 'Python type', 'JSON Schema Type', 'Additional JSON Schema', 'Defined in', 'Notes', ] table_text = _generate_table_heading(col_names) with (THIS_DIR / 'schema_mappings.toml').open('rb') as f: table = tomli.load(f) for t in table.values(): py_type = t['py_type'] json_type = t['json_type'] additional = t['additional'] defined_in = t['defined_in'] notes = t['notes'] if additional and not isinstance(additional, str): additional = json.dumps(additional) cols = [f'`{py_type}`', f'`{json_type}`', f'`{additional}`' if additional else '', defined_in, notes] table_text += _generate_table_row(cols) return re.sub(r'{{ *schema_mappings_table *}}', table_text, markdown) def build_conversion_table(markdown: str, page: Page) -> str | None: if page.file.src_uri != 'concepts/conversion_table.md': return None filtered_table_predicates = { 'all': lambda r: True, 'json': lambda r: r.json_input, 'json_strict': lambda r: r.json_input and r.strict, 'python': lambda r: r.python_input, 'python_strict': lambda r: r.python_input and r.strict, } for table_id, predicate in filtered_table_predicates.items(): table_markdown = conversion_table.filtered(predicate).as_markdown() table_markdown = textwrap.indent(table_markdown, ' ') markdown = re.sub(rf'{{{{ *conversion_table_{table_id} *}}}}', table_markdown, markdown) return markdown def devtools_example(markdown: str, page: Page) -> str | None: if page.file.src_uri != 'integrations/devtools.md': return None html = (THIS_DIR / 'devtools_output.html').read_text().strip('\n') full_html = f'
\n
{html}
\n
' return re.sub(r'{{ *devtools_example *}}', full_html, markdown) experts_template = Template( """
{% for user in people.experts %}
@{{ user.login }}
Questions replied: {{ user.count }}
{% endfor %}
""" ) most_active_users_template = Template( """
{% for user in people.last_month_active %}
@{{ user.login }}
Questions replied: {{ user.count }}
{% endfor %}
""" ) top_contributors_template = Template( """
{% for user in people.top_contributors %}
@{{ user.login }}
Contributions: {{ user.count }}
{% endfor %}
""" ) top_reviewers_template = Template( """
{% for user in people.top_reviewers %}
@{{ user.login }}
Reviews: {{ user.count }}
{% endfor %}
""" ) maintainers_template = Template( """
{% for user in people.maintainers %} {% endfor %}
""" ) def populate_pydantic_people(markdown: str, page: Page) -> str | None: if page.file.src_uri != 'pydantic_people.md': return None # read people.yml file data with (THIS_DIR / 'people.yml').open('rb') as f: people = yaml.load(f, Loader=yaml.FullLoader) # Render the templates for name, template in [ ('experts', experts_template), ('most_active_users', most_active_users_template), ('top_contributors', top_contributors_template), ('top_reviewers', top_reviewers_template), ('maintainers', maintainers_template), ]: rendered = template.render(people=people) markdown = re.sub(f'{{{{ {name} }}}}', rendered, markdown) return markdown pydantic-pydantic-ba0aa01/docs/plugins/orgs.toml000066400000000000000000000144001517143232300220650ustar00rootroot00000000000000[[orgs]] key = "adobe" name = "Adobe" description = """ [`adobe/dy-sql`](https://github.com/adobe/dy-sql) uses Pydantic. """ [[orgs]] key = "amazon" name = "Amazon and AWS" description = """ * [powertools-lambda-python](https://github.com/aws-powertools/powertools-lambda-python) * [awslabs/gluonts](https://github.com/awslabs/gluonts) * AWS [sponsored Samuel Colvin $5,000](https://twitter.com/samuel_colvin/status/1549383169006239745) to work on Pydantic in 2022 """ [[orgs]] key = "anthropic" name = "Anthropic" description = """ [`anthropics/anthropic-sdk-python`](https://github.com/anthropics/anthropic-sdk-python) uses Pydantic. """ [[orgs]] key = "apple" name = "Apple" [[orgs]] key = "asml" name = "ASML" [[orgs]] key = "astrazeneca" name = "AstraZeneca" description = """ [Multiple repos](https://github.com/search?q=org%3AAstraZeneca+pydantic&type=code) in the `AstraZeneca` GitHub org depend on Pydantic. """ [[orgs]] key = "cisco" name = "Cisco Systems" description = """ * Pydantic is listed in their report of [Open Source Used In RADKit](https://www.cisco.com/c/dam/en_us/about/doing_business/open_source/docs/RADKit-149-1687424532.pdf). * [`cisco/webex-assistant-sdk`](https://github.com/cisco/webex-assistant-sdk) """ [[orgs]] key = "capital_one" name = "Capital One" [[orgs]] key = "comcast" name = "Comcast" [[orgs]] key = "datadog" name = "Datadog" description = """ * Extensive use of Pydantic in [`DataDog/integrations-core`](https://github.com/DataDog/integrations-core) and other repos * Communication with engineers from Datadog about how they use Pydantic. """ [[orgs]] key = "facebook" name = "Facebook" description = """ [Multiple repos](https://github.com/search?q=org%3Afacebookresearch+pydantic&type=code) in the `facebookresearch` GitHub org depend on Pydantic. """ [[orgs]] key = "github" name = "GitHub" description = """ GitHub sponsored Pydantic $750 in 2022 """ [[orgs]] key = "google" name = "Google" description = """ Extensive use of Pydantic in [`google/turbinia`](https://github.com/google/turbinia) and other repos. """ [[orgs]] key = "hsbc" name = "HSBC" [[orgs]] key = "ibm" name = "IBM" description = """ [Multiple repos](https://github.com/search?q=org%3AIBM+pydantic&type=code) in the `IBM` GitHub org depend on Pydantic. """ [[orgs]] key = "intel" name = "Intel" [[orgs]] key = "intuit" name = "Intuit" [[orgs]] key = "ipcc" name = "Intergovernmental Panel on Climate Change" description = """ [Tweet](https://twitter.com/daniel_huppmann/status/1563461797973110785) explaining how the IPCC use Pydantic. """ [[orgs]] key = "jpmorgan" name = "JPMorgan" [[orgs]] key = "jupyter" name = "Jupyter" description = """ * The developers of the Jupyter notebook are using Pydantic [for subprojects](https://github.com/pydantic/pydantic/issues/773) * Through the FastAPI-based Jupyter server [Jupyverse](https://github.com/jupyter-server/jupyverse) * [FPS](https://github.com/jupyter-server/fps)'s configuration management. """ [[orgs]] key = "microsoft" name = "Microsoft" description = """ * [DeepSpeed](https://github.com/microsoft/DeepSpeed) deep learning optimisation library uses Pydantic extensively * [Multiple repos](https://github.com/search?q=org%3Amicrosoft%20pydantic&type=code) in the `microsoft` GitHub org depend on Pydantic, in particular their * Pydantic is also [used](https://github.com/search?q=org%3AAzure%20pydantic&type=code) in the `Azure` GitHub org * [Comments](https://github.com/tiangolo/fastapi/pull/26) on GitHub show Microsoft engineers using Pydantic as part of Windows and Office """ [[orgs]] key = "molssi" name = "Molecular Science Software Institute" description = """ [Multiple repos](https://github.com/search?q=org%3AMolSSI%20pydantic&type=code) in the `MolSSI` GitHub org depend on Pydantic. """ [[orgs]] key = "nasa" name = "NASA" description = """ [Multiple repos](https://github.com/search?q=org%3Anasa%20pydantic&type=code) in the `NASA` GitHub org depend on Pydantic. NASA are also using Pydantic via FastAPI in their JWST project to process images from the James Webb Space Telescope, see [this tweet](https://twitter.com/benjamin_falk/status/1546947039363305472). """ [[orgs]] key = "netflix" name = "Netflix" description = """ [Multiple repos](https://github.com/search?q=org%3Anetflix%20pydantic&type=code) in the `Netflix` GitHub org depend on Pydantic. """ [[orgs]] key = "nsa" name = "NSA" description = """ The [`nsacyber/WALKOFF`](https://github.com/nsacyber/WALKOFF) repo depends on Pydantic. """ [[orgs]] key = "nvidia" name = "NVIDIA" description = """ [Multiple repositories](https://github.com/search?q=org%3ANVIDIA%20pydantic&type=code) in the `NVIDIA` GitHub org depend on Pydantic. Their "Omniverse Services" depends on Pydantic according to [their documentation](https://web.archive.org/web/20220628161919/https://docs.omniverse.nvidia.com/prod_services/prod_services/core/index.html). """ [[orgs]] key = "openai" name = "OpenAI" description = """ OpenAI use Pydantic for their ChatCompletions API, as per [this](https://github.com/pydantic/pydantic/discussions/6372) discussion on GitHub. Anecdotally, OpenAI use Pydantic extensively for their internal services. """ [[orgs]] key = "oracle" name = "Oracle" [[orgs]] key = "palantir" name = "Palantir" [[orgs]] key = "qualcomm" name = "Qualcomm" [[orgs]] key = "redhat" name = "Red Hat" [[orgs]] key = "revolut" name = "Revolut" description = """ Anecdotally, all internal services at Revolut are built with FastAPI and therefore Pydantic. """ [[orgs]] key = "robusta" name = "Robusta" description = """ The [`robusta-dev/robusta`](https://github.com/robusta-dev/robusta) repo depends on Pydantic. """ [[orgs]] key = "salesforce" name = "Salesforce" description = """ Salesforce [sponsored Samuel Colvin $10,000](https://twitter.com/samuel_colvin/status/1501288247670063104) to work on Pydantic in 2022. """ [[orgs]] key = "starbucks" name = "Starbucks" [[orgs]] key = "ti" name = "Texas Instruments" [[orgs]] key = "twilio" name = "Twilio" [[orgs]] key = "twitter" name = "Twitter" description = """ Twitter's [`the-algorithm`](https://github.com/twitter/the-algorithm) repo where they [open sourced](https://blog.twitter.com/engineering/en_us/topics/open-source/2023/twitter-recommendation-algorithm) their recommendation engine uses Pydantic. """ [[orgs]] key = "ukhomeoffice" name = "UK Home Office" pydantic-pydantic-ba0aa01/docs/plugins/people.yml000066400000000000000000000461221517143232300222330ustar00rootroot00000000000000maintainers: - login: samuelcolvin answers: 296 prs: 408 avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=42eb3b833047c8c4b4f647a031eaef148c16d93f&v=4 url: https://github.com/samuelcolvin - login: dmontagu answers: 55 prs: 316 avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=540f30c937a6450812628b9592a1dfe91bbe148e&v=4 url: https://github.com/dmontagu - login: davidhewitt answers: 2 prs: 89 avatarUrl: https://avatars.githubusercontent.com/u/1939362?u=b4b48981c3a097daaad16c4c5417aa7a3e5e32d9&v=4 url: https://github.com/davidhewitt - login: Viicos answers: 232 prs: 491 avatarUrl: https://avatars.githubusercontent.com/u/65306057?u=fcd677dc1b9bef12aa103613e5ccb3f8ce305af9&v=4 url: https://github.com/Viicos - login: adriangb answers: 42 prs: 199 avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=612704256e38d6ac9cbed24f10e4b6ac2da74ecb&v=4 url: https://github.com/adriangb - login: alexmojaki answers: 0 prs: 18 avatarUrl: https://avatars.githubusercontent.com/u/3627481?u=9bb2e0cf1c5ef3d0609d2e639a135b7b4ca8b463&v=4 url: https://github.com/alexmojaki - login: Kludex answers: 22 prs: 112 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=df8a3f06ba8f55ae1967a3e2d5ed882903a4e330&v=4 url: https://github.com/Kludex - login: hramezani answers: 23 prs: 199 avatarUrl: https://avatars.githubusercontent.com/u/3122442?u=f387fc2dbc0c681f23e80e2ad705790fafcec9a2&v=4 url: https://github.com/hramezani experts: - login: samuelcolvin count: 296 avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=42eb3b833047c8c4b4f647a031eaef148c16d93f&v=4 url: https://github.com/samuelcolvin - login: Viicos count: 232 avatarUrl: https://avatars.githubusercontent.com/u/65306057?u=fcd677dc1b9bef12aa103613e5ccb3f8ce305af9&v=4 url: https://github.com/Viicos - login: PrettyWood count: 143 avatarUrl: https://avatars.githubusercontent.com/u/18406791?u=4853940cf5eeffb5bbb9ba06ad862f28bc68d69e&v=4 url: https://github.com/PrettyWood - login: uriyyo count: 96 avatarUrl: https://avatars.githubusercontent.com/u/32038156?u=c26ca9b821fcf6499b84db75f553d4980bf8d023&v=4 url: https://github.com/uriyyo - login: dmontagu count: 55 avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=540f30c937a6450812628b9592a1dfe91bbe148e&v=4 url: https://github.com/dmontagu - login: adriangb count: 42 avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=612704256e38d6ac9cbed24f10e4b6ac2da74ecb&v=4 url: https://github.com/adriangb - login: sydney-runkle count: 38 avatarUrl: https://avatars.githubusercontent.com/u/54324534?u=acc3756515d6f87acc91e36a4478557cba9d9dac&v=4 url: https://github.com/sydney-runkle - login: hramezani count: 23 avatarUrl: https://avatars.githubusercontent.com/u/3122442?u=f387fc2dbc0c681f23e80e2ad705790fafcec9a2&v=4 url: https://github.com/hramezani - login: Kludex count: 22 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=df8a3f06ba8f55ae1967a3e2d5ed882903a4e330&v=4 url: https://github.com/Kludex - login: lesnik512 count: 21 avatarUrl: https://avatars.githubusercontent.com/u/2184855?u=5670768b7efda993c4887d91df3cf330dc7bc9de&v=4 url: https://github.com/lesnik512 - login: harunyasar count: 17 avatarUrl: https://avatars.githubusercontent.com/u/1765494?u=5b1ab7c582db4b4016fa31affe977d10af108ad4&v=4 url: https://github.com/harunyasar - login: janas-adam count: 15 avatarUrl: https://avatars.githubusercontent.com/u/48211033?u=5ca15d25319ce589da76d7891144ddc8480d8b6d&v=4 url: https://github.com/janas-adam - login: nymous count: 13 avatarUrl: https://avatars.githubusercontent.com/u/4216559?u=360a36fb602cded27273cbfc0afc296eece90662&v=4 url: https://github.com/nymous - login: ybressler count: 3 avatarUrl: https://avatars.githubusercontent.com/u/40807730?v=4 url: https://github.com/ybressler last_month_active: - login: Viicos count: 3 avatarUrl: https://avatars.githubusercontent.com/u/65306057?u=fcd677dc1b9bef12aa103613e5ccb3f8ce305af9&v=4 url: https://github.com/Viicos top_contributors: - login: Viicos count: 491 avatarUrl: https://avatars.githubusercontent.com/u/65306057?u=fcd677dc1b9bef12aa103613e5ccb3f8ce305af9&v=4 url: https://github.com/Viicos - login: samuelcolvin count: 408 avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=42eb3b833047c8c4b4f647a031eaef148c16d93f&v=4 url: https://github.com/samuelcolvin - login: sydney-runkle count: 382 avatarUrl: https://avatars.githubusercontent.com/u/54324534?u=acc3756515d6f87acc91e36a4478557cba9d9dac&v=4 url: https://github.com/sydney-runkle - login: dmontagu count: 316 avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=540f30c937a6450812628b9592a1dfe91bbe148e&v=4 url: https://github.com/dmontagu - login: adriangb count: 199 avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=612704256e38d6ac9cbed24f10e4b6ac2da74ecb&v=4 url: https://github.com/adriangb - login: hramezani count: 199 avatarUrl: https://avatars.githubusercontent.com/u/3122442?u=f387fc2dbc0c681f23e80e2ad705790fafcec9a2&v=4 url: https://github.com/hramezani - login: PrettyWood count: 122 avatarUrl: https://avatars.githubusercontent.com/u/18406791?u=4853940cf5eeffb5bbb9ba06ad862f28bc68d69e&v=4 url: https://github.com/PrettyWood - login: Kludex count: 112 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=df8a3f06ba8f55ae1967a3e2d5ed882903a4e330&v=4 url: https://github.com/Kludex - login: davidhewitt count: 89 avatarUrl: https://avatars.githubusercontent.com/u/1939362?u=b4b48981c3a097daaad16c4c5417aa7a3e5e32d9&v=4 url: https://github.com/davidhewitt - login: tpdorsey count: 71 avatarUrl: https://avatars.githubusercontent.com/u/370316?u=eb206070cfe47f242d5fcea2e6c7514f4d0f27f5&v=4 url: https://github.com/tpdorsey - login: lig count: 49 avatarUrl: https://avatars.githubusercontent.com/u/38705?v=4 url: https://github.com/lig - login: pyup-bot count: 46 avatarUrl: https://avatars.githubusercontent.com/u/16239342?u=8454ae029661131445080f023e1efccc29166485&v=4 url: https://github.com/pyup-bot - login: tiangolo count: 22 avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4 url: https://github.com/tiangolo - login: Bobronium count: 19 avatarUrl: https://avatars.githubusercontent.com/u/36469655?u=f67d8fa6d67d35d2f5ebd5b15e24efeb41036fd3&v=4 url: https://github.com/Bobronium - login: alexmojaki count: 18 avatarUrl: https://avatars.githubusercontent.com/u/3627481?u=9bb2e0cf1c5ef3d0609d2e639a135b7b4ca8b463&v=4 url: https://github.com/alexmojaki - login: Gr1N count: 17 avatarUrl: https://avatars.githubusercontent.com/u/1087619?u=cd78c4f602bf9f9667277dd0af9302a7fe9dd75a&v=4 url: https://github.com/Gr1N - login: misrasaurabh1 count: 16 avatarUrl: https://avatars.githubusercontent.com/u/1271289?u=b83b0a82b2c95990d93cefbeb8f548d9f2f090c2&v=4 url: https://github.com/misrasaurabh1 - login: uriyyo count: 15 avatarUrl: https://avatars.githubusercontent.com/u/32038156?u=c26ca9b821fcf6499b84db75f553d4980bf8d023&v=4 url: https://github.com/uriyyo - login: pilosus count: 12 avatarUrl: https://avatars.githubusercontent.com/u/6400248?u=88cadd1dd6376e7000934e93712c5eb0138c1616&v=4 url: https://github.com/pilosus - login: yezz123 count: 12 avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=21b53ce4115062b1e20cb513e64ca0000c2ef127&v=4 url: https://github.com/yezz123 - login: cdce8p count: 12 avatarUrl: https://avatars.githubusercontent.com/u/30130371?v=4 url: https://github.com/cdce8p - login: kc0506 count: 12 avatarUrl: https://avatars.githubusercontent.com/u/89458301?u=75f53e971fcba3ff61836c389505a420bddd865c&v=4 url: https://github.com/kc0506 - login: StephenBrown2 count: 10 avatarUrl: https://avatars.githubusercontent.com/u/1148665?u=b69e6fe797302f025a2d125e377e27f8ea0b8058&v=4 url: https://github.com/StephenBrown2 - login: koxudaxi count: 9 avatarUrl: https://avatars.githubusercontent.com/u/630670?u=507d8577b4b3670546b449c4c2ccbc5af40d72f7&v=4 url: https://github.com/koxudaxi - login: aminalaee count: 8 avatarUrl: https://avatars.githubusercontent.com/u/19784933?v=4 url: https://github.com/aminalaee - login: NeevCohen count: 8 avatarUrl: https://avatars.githubusercontent.com/u/70970900?u=573a3175906348e0d1529104d56b391e93ca0250&v=4 url: https://github.com/NeevCohen - login: layday count: 7 avatarUrl: https://avatars.githubusercontent.com/u/31134424?u=e8afd95a97b5556c467d1be27788950e67378ef1&v=4 url: https://github.com/layday - login: daviskirk count: 7 avatarUrl: https://avatars.githubusercontent.com/u/1049817?u=b42e1148d23ea9039b325975bbea3ff8c5b4e3ec&v=4 url: https://github.com/daviskirk - login: tlambert03 count: 7 avatarUrl: https://avatars.githubusercontent.com/u/1609449?u=922abf0524b47739b37095e553c99488814b05db&v=4 url: https://github.com/tlambert03 - login: dgasmith count: 6 avatarUrl: https://avatars.githubusercontent.com/u/1769841?u=44e83d7974f0ab5c431340f1669d98f781594980&v=4 url: https://github.com/dgasmith - login: Atheuz count: 6 avatarUrl: https://avatars.githubusercontent.com/u/202696?v=4 url: https://github.com/Atheuz - login: cclauss count: 6 avatarUrl: https://avatars.githubusercontent.com/u/3709715?u=0745d1d2473894c33f3b35f0b965d71cc9aec553&v=4 url: https://github.com/cclauss - login: AdolfoVillalobos count: 6 avatarUrl: https://avatars.githubusercontent.com/u/16639270?u=faa71bcfb3273a32cd81711a56998e115bca7fcc&v=4 url: https://github.com/AdolfoVillalobos - login: DouweM count: 6 avatarUrl: https://avatars.githubusercontent.com/u/159434?u=45706bfe14e7ff6afceb81b01f8316efa808ee65&v=4 url: https://github.com/DouweM - login: nuno-andre count: 5 avatarUrl: https://avatars.githubusercontent.com/u/6339494?u=893876f31ce65fa8ad8cfcc592392a77f0f8af38&v=4 url: https://github.com/nuno-andre - login: ofek count: 5 avatarUrl: https://avatars.githubusercontent.com/u/9677399?u=386c330f212ce467ce7119d9615c75d0e9b9f1ce&v=4 url: https://github.com/ofek - login: JensHeinrich count: 5 avatarUrl: https://avatars.githubusercontent.com/u/59469646?u=86d6a20768cc4cc65622eafd86672147321bd8f8&v=4 url: https://github.com/JensHeinrich - login: ornariece count: 5 avatarUrl: https://avatars.githubusercontent.com/u/25489980?u=1e9b5cbbbb1516fbea6da00429e4eef0ef79e4e6&v=4 url: https://github.com/ornariece - login: mschoettle count: 5 avatarUrl: https://avatars.githubusercontent.com/u/9328433?u=8546519cb04223cd878285d72c27850b5f3f0882&v=4 url: https://github.com/mschoettle - login: karta9821 count: 5 avatarUrl: https://avatars.githubusercontent.com/u/44468031?u=1590b6d141e6cbcc1862a95959b9a134fdb1f108&v=4 url: https://github.com/karta9821 - login: Rohan5commit count: 5 avatarUrl: https://avatars.githubusercontent.com/u/181558744?u=e91b9d6f486298d4687e06be4a32857049ae4c2a&v=4 url: https://github.com/Rohan5commit - login: hmvp count: 4 avatarUrl: https://avatars.githubusercontent.com/u/1734544?v=4 url: https://github.com/hmvp - login: retnikt count: 4 avatarUrl: https://avatars.githubusercontent.com/u/24581770?v=4 url: https://github.com/retnikt - login: therefromhere count: 4 avatarUrl: https://avatars.githubusercontent.com/u/197540?v=4 url: https://github.com/therefromhere - login: JeanArhancet count: 4 avatarUrl: https://avatars.githubusercontent.com/u/10811879?v=4 url: https://github.com/JeanArhancet - login: commonism count: 4 avatarUrl: https://avatars.githubusercontent.com/u/164513?v=4 url: https://github.com/commonism - login: MarkusSintonen count: 4 avatarUrl: https://avatars.githubusercontent.com/u/12939780?v=4 url: https://github.com/MarkusSintonen top_reviewers: - login: samuelcolvin count: 706 avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=42eb3b833047c8c4b4f647a031eaef148c16d93f&v=4 url: https://github.com/samuelcolvin - login: sydney-runkle count: 691 avatarUrl: https://avatars.githubusercontent.com/u/54324534?u=acc3756515d6f87acc91e36a4478557cba9d9dac&v=4 url: https://github.com/sydney-runkle - login: Viicos count: 557 avatarUrl: https://avatars.githubusercontent.com/u/65306057?u=fcd677dc1b9bef12aa103613e5ccb3f8ce305af9&v=4 url: https://github.com/Viicos - login: hramezani count: 534 avatarUrl: https://avatars.githubusercontent.com/u/3122442?u=f387fc2dbc0c681f23e80e2ad705790fafcec9a2&v=4 url: https://github.com/hramezani - login: dmontagu count: 532 avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=540f30c937a6450812628b9592a1dfe91bbe148e&v=4 url: https://github.com/dmontagu - login: adriangb count: 428 avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=612704256e38d6ac9cbed24f10e4b6ac2da74ecb&v=4 url: https://github.com/adriangb - login: Kludex count: 261 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=df8a3f06ba8f55ae1967a3e2d5ed882903a4e330&v=4 url: https://github.com/Kludex - login: davidhewitt count: 260 avatarUrl: https://avatars.githubusercontent.com/u/1939362?u=b4b48981c3a097daaad16c4c5417aa7a3e5e32d9&v=4 url: https://github.com/davidhewitt - login: PrettyWood count: 211 avatarUrl: https://avatars.githubusercontent.com/u/18406791?u=4853940cf5eeffb5bbb9ba06ad862f28bc68d69e&v=4 url: https://github.com/PrettyWood - login: lig count: 103 avatarUrl: https://avatars.githubusercontent.com/u/38705?v=4 url: https://github.com/lig - login: tpdorsey count: 77 avatarUrl: https://avatars.githubusercontent.com/u/370316?u=eb206070cfe47f242d5fcea2e6c7514f4d0f27f5&v=4 url: https://github.com/tpdorsey - login: hyperlint-ai-deprecated count: 57 avatarUrl: https://avatars.githubusercontent.com/in/718456?v=4 url: https://github.com/apps/hyperlint-ai-deprecated - login: tiangolo count: 45 avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4 url: https://github.com/tiangolo - login: DouweM count: 43 avatarUrl: https://avatars.githubusercontent.com/u/159434?u=45706bfe14e7ff6afceb81b01f8316efa808ee65&v=4 url: https://github.com/DouweM - login: alexmojaki count: 33 avatarUrl: https://avatars.githubusercontent.com/u/3627481?u=9bb2e0cf1c5ef3d0609d2e639a135b7b4ca8b463&v=4 url: https://github.com/alexmojaki - login: Bobronium count: 27 avatarUrl: https://avatars.githubusercontent.com/u/36469655?u=f67d8fa6d67d35d2f5ebd5b15e24efeb41036fd3&v=4 url: https://github.com/Bobronium - login: friendlymatthew count: 21 avatarUrl: https://avatars.githubusercontent.com/u/38759997?u=d7ed300a53abb0765bfb12362203dd5255c29dee&v=4 url: https://github.com/friendlymatthew - login: Gr1N count: 17 avatarUrl: https://avatars.githubusercontent.com/u/1087619?u=cd78c4f602bf9f9667277dd0af9302a7fe9dd75a&v=4 url: https://github.com/Gr1N - login: StephenBrown2 count: 17 avatarUrl: https://avatars.githubusercontent.com/u/1148665?u=b69e6fe797302f025a2d125e377e27f8ea0b8058&v=4 url: https://github.com/StephenBrown2 - login: MarkusSintonen count: 16 avatarUrl: https://avatars.githubusercontent.com/u/12939780?v=4 url: https://github.com/MarkusSintonen - login: ybressler count: 15 avatarUrl: https://avatars.githubusercontent.com/u/40807730?u=fa12d64259ccf9eca18847102335ee6408cb9eaa&v=4 url: https://github.com/ybressler - login: uriyyo count: 11 avatarUrl: https://avatars.githubusercontent.com/u/32038156?u=c26ca9b821fcf6499b84db75f553d4980bf8d023&v=4 url: https://github.com/uriyyo - login: koxudaxi count: 10 avatarUrl: https://avatars.githubusercontent.com/u/630670?u=507d8577b4b3670546b449c4c2ccbc5af40d72f7&v=4 url: https://github.com/koxudaxi - login: daviskirk count: 10 avatarUrl: https://avatars.githubusercontent.com/u/1049817?u=b42e1148d23ea9039b325975bbea3ff8c5b4e3ec&v=4 url: https://github.com/daviskirk - login: yezz123 count: 10 avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=21b53ce4115062b1e20cb513e64ca0000c2ef127&v=4 url: https://github.com/yezz123 - login: Zac-HD count: 8 avatarUrl: https://avatars.githubusercontent.com/u/12229877?u=abc44dbce4bb3eca2def638bd0d4ab4cfef91b74&v=4 url: https://github.com/Zac-HD - login: layday count: 7 avatarUrl: https://avatars.githubusercontent.com/u/31134424?u=e8afd95a97b5556c467d1be27788950e67378ef1&v=4 url: https://github.com/layday - login: kc0506 count: 7 avatarUrl: https://avatars.githubusercontent.com/u/89458301?u=75f53e971fcba3ff61836c389505a420bddd865c&v=4 url: https://github.com/kc0506 - login: pilosus count: 6 avatarUrl: https://avatars.githubusercontent.com/u/6400248?u=88cadd1dd6376e7000934e93712c5eb0138c1616&v=4 url: https://github.com/pilosus - login: Kilo59 count: 6 avatarUrl: https://avatars.githubusercontent.com/u/13108583?u=0d34d39c0628091596c9d5ebb4e802009e8c4aca&v=4 url: https://github.com/Kilo59 - login: JeanArhancet count: 6 avatarUrl: https://avatars.githubusercontent.com/u/10811879?v=4 url: https://github.com/JeanArhancet - login: andresliszt count: 6 avatarUrl: https://avatars.githubusercontent.com/u/36001403?u=51045ee35d6c53867638517e8dcf817927d77e85&v=4 url: https://github.com/andresliszt - login: tlambert03 count: 5 avatarUrl: https://avatars.githubusercontent.com/u/1609449?u=922abf0524b47739b37095e553c99488814b05db&v=4 url: https://github.com/tlambert03 - login: christianbundy count: 5 avatarUrl: https://avatars.githubusercontent.com/u/537700?u=d6cc48076a656f94710d8e1266c92792b8c9d7c4&v=4 url: https://github.com/christianbundy - login: nix010 count: 5 avatarUrl: https://avatars.githubusercontent.com/u/16438204?u=f700f440b89e715795c3bc091800b8d3f39c58d9&v=4 url: https://github.com/nix010 - login: karta9821 count: 5 avatarUrl: https://avatars.githubusercontent.com/u/44468031?u=1590b6d141e6cbcc1862a95959b9a134fdb1f108&v=4 url: https://github.com/karta9821 - login: graingert count: 4 avatarUrl: https://avatars.githubusercontent.com/u/413772?v=4 url: https://github.com/graingert - login: hmvp count: 4 avatarUrl: https://avatars.githubusercontent.com/u/1734544?v=4 url: https://github.com/hmvp - login: wozniakty count: 4 avatarUrl: https://avatars.githubusercontent.com/u/5042313?u=8917c345dcb528733073ff1ce8a512e33f548512&v=4 url: https://github.com/wozniakty - login: nuno-andre count: 4 avatarUrl: https://avatars.githubusercontent.com/u/6339494?u=893876f31ce65fa8ad8cfcc592392a77f0f8af38&v=4 url: https://github.com/nuno-andre - login: antdking count: 4 avatarUrl: https://avatars.githubusercontent.com/u/2099618?u=a9899c1fea247d500e5368a1157a392bcd82e81d&v=4 url: https://github.com/antdking - login: dimaqq count: 4 avatarUrl: https://avatars.githubusercontent.com/u/662249?u=15313dec91bae789685e4abb3c2152251de41948&v=4 url: https://github.com/dimaqq - login: DetachHead count: 4 avatarUrl: https://avatars.githubusercontent.com/u/57028336?u=387c51980cb3734c41543ae2276a23736906bdb9&v=4 url: https://github.com/DetachHead - login: JensHeinrich count: 4 avatarUrl: https://avatars.githubusercontent.com/u/59469646?u=86d6a20768cc4cc65622eafd86672147321bd8f8&v=4 url: https://github.com/JensHeinrich - login: cclauss count: 4 avatarUrl: https://avatars.githubusercontent.com/u/3709715?u=0745d1d2473894c33f3b35f0b965d71cc9aec553&v=4 url: https://github.com/cclauss pydantic-pydantic-ba0aa01/docs/plugins/schema_mappings.toml000066400000000000000000000310141517143232300242510ustar00rootroot00000000000000[None] py_type = "None" json_type = "null" additional = "" defined_in = "JSON Schema Core" notes = "Same for `type(None)` or `Literal[None]`" [bool] py_type = "bool" json_type = "boolean" additional = "" defined_in = "JSON Schema Core" notes = "" [str] py_type = "str" json_type = "string" additional = "" defined_in = "JSON Schema Core" notes = "" [float] py_type = "float" json_type = "number" additional = "" defined_in = "JSON Schema Core" notes = "" [int] py_type = "int" json_type = "integer" additional = "" defined_in = "JSON Schema Validation" notes = "" [dict] py_type = "dict" json_type = "object" additional = "" defined_in = "JSON Schema Core" notes = "" [list] py_type = "list" json_type = "array" defined_in = "JSON Schema Core" notes = "" [list.additional.items] [tuple-positional] py_type = "tuple-positional" json_type = "array" defined_in = "JSON Schema Core" notes = "" [tuple-positional.additional.items] [tuple-variable] py_type = "tuple-variable" json_type = "array" defined_in = "JSON Schema Core" notes = "" [tuple-variable.additional.items] [set] py_type = "set" json_type = "array" defined_in = "JSON Schema Validation" notes = "" [set.additional] uniqueItems = true [set.additional.items] [frozenset] py_type = "frozenset" json_type = "array" defined_in = "JSON Schema Validation" notes = "" [frozenset.additional] uniqueItems = true [frozenset.additional.items] ["List[str]"] py_type = "List[str]" json_type = "array" defined_in = "JSON Schema Validation" notes = "And equivalently for any other sub type, e.g. `List[int]`." ["List[str]".additional.items] type = "string" ["Tuple[str, ...]"] py_type = "Tuple[str, ...]" json_type = "array" defined_in = "JSON Schema Validation" notes = "And equivalently for any other sub type, e.g. `Tuple[int, ...]`." ["Tuple[str, ...]".additional.items] type = "string" ["Tuple[str, int]"] py_type = "Tuple[str, int]" json_type = "array" defined_in = "JSON Schema Validation" notes = "And equivalently for any other set of subtypes. Note: If using schemas for OpenAPI, you shouldn't use this declaration, as it would not be valid in OpenAPI (although it is valid in JSON Schema)." ["Tuple[str, int]".additional] minItems = 2 maxItems = 2 [["Tuple[str, int]".additional.items]] type = "string" [["Tuple[str, int]".additional.items]] type = "integer" ["Dict[str, int]"] py_type = "Dict[str, int]" json_type = "object" defined_in = "JSON Schema Validation" notes = "And equivalently for any other subfields for dicts. Have in mind that although you can use other types as keys for dicts with Pydantic, only strings are valid keys for JSON, and so, only str is valid as JSON Schema key types." ["Dict[str, int]".additional.additionalProperties] type = "integer" ["Union[str, int]"] py_type = "Union[str, int]" json_type = "anyOf" defined_in = "JSON Schema Validation" notes = "And equivalently for any other subfields for unions." [["Union[str, int]".additional.anyOf]] type = "string" [["Union[str, int]".additional.anyOf]] type = "integer" [Enum] py_type = "Enum" json_type = "enum" additional = "{\"enum\": [...]}" defined_in = "JSON Schema Validation" notes = "All the literal values in the enum are included in the definition." [SecretStr] py_type = "SecretStr" json_type = "string" defined_in = "JSON Schema Validation" notes = "" [SecretStr.additional] writeOnly = true [SecretBytes] py_type = "SecretBytes" json_type = "string" defined_in = "JSON Schema Validation" notes = "" [SecretBytes.additional] writeOnly = true [EmailStr] py_type = "EmailStr" json_type = "string" defined_in = "JSON Schema Validation" notes = "" [EmailStr.additional] format = "email" [NameEmail] py_type = "NameEmail" json_type = "string" defined_in = "Pydantic standard \"format\" extension" notes = "" [NameEmail.additional] format = "name-email" [AnyUrl] py_type = "AnyUrl" json_type = "string" defined_in = "JSON Schema Validation" notes = "" [AnyUrl.additional] format = "uri" [Pattern] py_type = "Pattern" json_type = "string" defined_in = "JSON Schema Validation" notes = "" [Pattern.additional] format = "regex" [bytes] py_type = "bytes" json_type = "string" defined_in = "OpenAPI" notes = "" [bytes.additional] format = "binary" [Decimal] py_type = "Decimal" json_type = "number" additional = "" defined_in = "JSON Schema Core" notes = "" [UUID1] py_type = "UUID1" json_type = "string" defined_in = "Pydantic standard \"format\" extension" notes = "" [UUID1.additional] format = "uuid1" [UUID3] py_type = "UUID3" json_type = "string" defined_in = "Pydantic standard \"format\" extension" notes = "" [UUID3.additional] format = "uuid3" [UUID4] py_type = "UUID4" json_type = "string" defined_in = "Pydantic standard \"format\" extension" notes = "" [UUID4.additional] format = "uuid4" [UUID5] py_type = "UUID5" json_type = "string" defined_in = "Pydantic standard \"format\" extension" notes = "" [UUID5.additional] format = "uuid5" [UUID] py_type = "UUID" json_type = "string" defined_in = "Pydantic standard \"format\" extension" notes = "Suggested in OpenAPI." [UUID.additional] format = "uuid" [FilePath] py_type = "FilePath" json_type = "string" defined_in = "Pydantic standard \"format\" extension" notes = "" [FilePath.additional] format = "file-path" [DirectoryPath] py_type = "DirectoryPath" json_type = "string" defined_in = "Pydantic standard \"format\" extension" notes = "" [DirectoryPath.additional] format = "directory-path" [Path] py_type = "Path" json_type = "string" defined_in = "Pydantic standard \"format\" extension" notes = "" [Path.additional] format = "path" [datetime] py_type = "datetime" json_type = "string" defined_in = "JSON Schema Validation" notes = "" [datetime.additional] format = "date-time" [date] py_type = "date" json_type = "string" defined_in = "JSON Schema Validation" notes = "" [date.additional] format = "date" [time] py_type = "time" json_type = "string" defined_in = "JSON Schema Validation" notes = "" [time.additional] format = "time" [timedelta] py_type = "timedelta" json_type = "number" defined_in = "Difference in seconds (a `float`), with Pydantic standard \"format\" extension" notes = "Suggested in JSON Schema repository's issues by maintainer." [timedelta.additional] format = "time-delta" [Json] py_type = "Json" json_type = "string" defined_in = "Pydantic standard \"format\" extension" notes = "" [Json.additional] format = "json-string" [IPv4Address] py_type = "IPv4Address" json_type = "string" defined_in = "JSON Schema Validation" notes = "" [IPv4Address.additional] format = "ipv4" [IPv6Address] py_type = "IPv6Address" json_type = "string" defined_in = "JSON Schema Validation" notes = "" [IPv6Address.additional] format = "ipv6" [IPvAnyAddress] py_type = "IPvAnyAddress" json_type = "string" defined_in = "Pydantic standard \"format\" extension" notes = "IPv4 or IPv6 address as used in `ipaddress` module" [IPvAnyAddress.additional] format = "ipvanyaddress" [IPv4Interface] py_type = "IPv4Interface" json_type = "string" defined_in = "Pydantic standard \"format\" extension" notes = "IPv4 interface as used in `ipaddress` module" [IPv4Interface.additional] format = "ipv4interface" [IPv6Interface] py_type = "IPv6Interface" json_type = "string" defined_in = "Pydantic standard \"format\" extension" notes = "IPv6 interface as used in `ipaddress` module" [IPv6Interface.additional] format = "ipv6interface" [IPvAnyInterface] py_type = "IPvAnyInterface" json_type = "string" defined_in = "Pydantic standard \"format\" extension" notes = "IPv4 or IPv6 interface as used in `ipaddress` module" [IPvAnyInterface.additional] format = "ipvanyinterface" [IPv4Network] py_type = "IPv4Network" json_type = "string" defined_in = "Pydantic standard \"format\" extension" notes = "IPv4 network as used in `ipaddress` module" [IPv4Network.additional] format = "ipv4network" [IPv6Network] py_type = "IPv6Network" json_type = "string" defined_in = "Pydantic standard \"format\" extension" notes = "IPv6 network as used in `ipaddress` module" [IPv6Network.additional] format = "ipv6network" [IPvAnyNetwork] py_type = "IPvAnyNetwork" json_type = "string" defined_in = "Pydantic standard \"format\" extension" notes = "IPv4 or IPv6 network as used in `ipaddress` module" [IPvAnyNetwork.additional] format = "ipvanynetwork" [StrictBool] py_type = "StrictBool" json_type = "boolean" additional = "" defined_in = "JSON Schema Core" notes = "" [StrictStr] py_type = "StrictStr" json_type = "string" additional = "" defined_in = "JSON Schema Core" notes = "" [ConstrainedStr] py_type = "ConstrainedStr" json_type = "string" additional = "" defined_in = "JSON Schema Core" notes = "If the type has values declared for the constraints, they are included as validations. See the mapping for `constr` below." ["constr(pattern='^text$', min_length=2, max_length=10)"] py_type = "constr(pattern='^text$', min_length=2, max_length=10)" json_type = "string" defined_in = "JSON Schema Validation" notes = "Any argument not passed to the function (not defined) will not be included in the schema." ["constr(pattern='^text$', min_length=2, max_length=10)".additional] pattern = "^text$" minLength = 2 maxLength = 10 [ConstrainedInt] py_type = "ConstrainedInt" json_type = "integer" additional = "" defined_in = "JSON Schema Core" notes = "If the type has values declared for the constraints, they are included as validations. See the mapping for `conint` below." ["conint(gt=1, ge=2, lt=6, le=5, multiple_of=2)"] py_type = "conint(gt=1, ge=2, lt=6, le=5, multiple_of=2)" json_type = "integer" defined_in = "" notes = "Any argument not passed to the function (not defined) will not be included in the schema." ["conint(gt=1, ge=2, lt=6, le=5, multiple_of=2)".additional] maximum = 5 exclusiveMaximum = 6 minimum = 2 exclusiveMinimum = 1 multipleOf = 2 [PositiveInt] py_type = "PositiveInt" json_type = "integer" defined_in = "JSON Schema Validation" notes = "" [PositiveInt.additional] exclusiveMinimum = 0 [NegativeInt] py_type = "NegativeInt" json_type = "integer" defined_in = "JSON Schema Validation" notes = "" [NegativeInt.additional] exclusiveMaximum = 0 [NonNegativeInt] py_type = "NonNegativeInt" json_type = "integer" defined_in = "JSON Schema Validation" notes = "" [NonNegativeInt.additional] minimum = 0 [NonPositiveInt] py_type = "NonPositiveInt" json_type = "integer" defined_in = "JSON Schema Validation" notes = "" [NonPositiveInt.additional] maximum = 0 [ConstrainedFloat] py_type = "ConstrainedFloat" json_type = "number" additional = "" defined_in = "JSON Schema Core" notes = "If the type has values declared for the constraints, they are included as validations. See the mapping for `confloat` below." ["confloat(gt=1, ge=2, lt=6, le=5, multiple_of=2)"] py_type = "confloat(gt=1, ge=2, lt=6, le=5, multiple_of=2)" json_type = "number" defined_in = "JSON Schema Validation" notes = "Any argument not passed to the function (not defined) will not be included in the schema." ["confloat(gt=1, ge=2, lt=6, le=5, multiple_of=2)".additional] maximum = 5 exclusiveMaximum = 6 minimum = 2 exclusiveMinimum = 1 multipleOf = 2 [PositiveFloat] py_type = "PositiveFloat" json_type = "number" defined_in = "JSON Schema Validation" notes = "" [PositiveFloat.additional] exclusiveMinimum = 0 [NegativeFloat] py_type = "NegativeFloat" json_type = "number" defined_in = "JSON Schema Validation" notes = "" [NegativeFloat.additional] exclusiveMaximum = 0 [NonNegativeFloat] py_type = "NonNegativeFloat" json_type = "number" defined_in = "JSON Schema Validation" notes = "" [NonNegativeFloat.additional] minimum = 0 [NonPositiveFloat] py_type = "NonPositiveFloat" json_type = "number" defined_in = "JSON Schema Validation" notes = "" [NonPositiveFloat.additional] maximum = 0 [ConstrainedDecimal] py_type = "ConstrainedDecimal" json_type = "number" additional = "" defined_in = "JSON Schema Core" notes = "If the type has values declared for the constraints, they are included as validations. See the mapping for `condecimal` below." ["condecimal(gt=1, ge=2, lt=6, le=5, multiple_of=2)"] py_type = "condecimal(gt=1, ge=2, lt=6, le=5, multiple_of=2)" json_type = "number" defined_in = "JSON Schema Validation" notes = "Any argument not passed to the function (not defined) will not be included in the schema." ["condecimal(gt=1, ge=2, lt=6, le=5, multiple_of=2)".additional] maximum = 5 exclusiveMaximum = 6 minimum = 2 exclusiveMinimum = 1 multipleOf = 2 [BaseModel] py_type = "BaseModel" json_type = "object" additional = "" defined_in = "JSON Schema Core" notes = "All the properties defined will be defined with standard JSON Schema, including submodels." [Color] py_type = "Color" json_type = "string" defined_in = "Pydantic standard \"format\" extension" notes = "" [Color.additional] format = "color" pydantic-pydantic-ba0aa01/docs/plugins/using.toml000066400000000000000000000052121517143232300222410ustar00rootroot00000000000000[[libs]] repo = "huggingface/transformers" stars = 138570 [[libs]] repo = "hwchase17/langchain" stars = 99542 [[libs]] repo = "tiangolo/fastapi" stars = 80497 [[libs]] repo = "apache/airflow" stars = 38577 [[libs]] repo = "lm-sys/FastChat" stars = 37650 [[libs]] repo = "microsoft/DeepSpeed" stars = 36521 [[libs]] repo = "OpenBB-finance/OpenBBTerminal" stars = 35971 [[libs]] repo = "gradio-app/gradio" stars = 35740 [[libs]] repo = "ray-project/ray" stars = 35176 [[libs]] repo = "pola-rs/polars" stars = 31698 [[libs]] repo = "Lightning-AI/lightning" stars = 28902 [[libs]] repo = "mindsdb/mindsdb" stars = 27141 [[libs]] repo = "embedchain/embedchain" stars = 24379 [[libs]] repo = "pynecone-io/reflex" stars = 21558 [[libs]] repo = "heartexlabs/label-studio" stars = 20571 [[libs]] repo = "Sanster/lama-cleaner" stars = 20313 [[libs]] repo = "mlflow/mlflow" stars = 19393 [[libs]] repo = "RasaHQ/rasa" stars = 19337 [[libs]] repo = "spotDL/spotify-downloader" stars = 18604 [[libs]] repo = "chroma-core/chroma" stars = 17393 [[libs]] repo = "airbytehq/airbyte" stars = 17120 [[libs]] repo = "openai/evals" stars = 15437 [[libs]] repo = "tiangolo/sqlmodel" stars = 15127 [[libs]] repo = "ydataai/ydata-profiling" stars = 12687 [[libs]] repo = "pyodide/pyodide" stars = 12653 [[libs]] repo = "dagster-io/dagster" stars = 12440 [[libs]] repo = "PaddlePaddle/PaddleNLP" stars = 12312 [[libs]] repo = "matrix-org/synapse" stars = 11857 [[libs]] repo = "lucidrains/DALLE2-pytorch" stars = 11207 [[libs]] repo = "great-expectations/great_expectations" stars = 10164 [[libs]] repo = "modin-project/modin" stars = 10002 [[libs]] repo = "aws/serverless-application-model" stars = 9402 [[libs]] repo = "sqlfluff/sqlfluff" stars = 8535 [[libs]] repo = "replicate/cog" stars = 8344 [[libs]] repo = "autogluon/autogluon" stars = 8326 [[libs]] repo = "lucidrains/imagen-pytorch" stars = 8164 [[libs]] repo = "brycedrennan/imaginAIry" stars = 8050 [[libs]] repo = "vitalik/django-ninja" stars = 7685 [[libs]] repo = "NVlabs/SPADE" stars = 7632 [[libs]] repo = "bridgecrewio/checkov" stars = 7340 [[libs]] repo = "bentoml/BentoML" stars = 7322 [[libs]] repo = "skypilot-org/skypilot" stars = 7113 [[libs]] repo = "apache/iceberg" stars = 6853 [[libs]] repo = "deeppavlov/DeepPavlov" stars = 6777 [[libs]] repo = "PrefectHQ/marvin" stars = 5454 [[libs]] repo = "NVIDIA/NeMo-Guardrails" stars = 4383 [[libs]] repo = "microsoft/FLAML" stars = 4035 [[libs]] repo = "jina-ai/discoart" stars = 3846 [[libs]] repo = "docarray/docarray" stars = 3007 [[libs]] repo = "aws-powertools/powertools-lambda-python" stars = 2980 [[libs]] repo = "roman-right/beanie" stars = 2172 [[libs]] repo = "art049/odmantic" stars = 1096 pydantic-pydantic-ba0aa01/docs/plugins/using_update.py000066400000000000000000000016151517143232300232630ustar00rootroot00000000000000from pathlib import Path from time import sleep import requests import tomli THIS_DIR = Path(__file__).parent session = requests.Session() def update_lib(lib, *, retry=0): repo = lib['repo'] url = f'https://api.github.com/repos/{repo}' resp = session.get(url) if resp.status_code == 403 and retry < 3: print(f'retrying {repo} {retry}') sleep(5) return update_lib(lib, retry=retry + 1) resp.raise_for_status() data = resp.json() stars = data['watchers_count'] print(f'{repo}: {stars}') lib['stars'] = stars with (THIS_DIR / 'using.toml').open('rb') as f: table = tomli.load(f) libs = table['libs'] for lib in libs: update_lib(lib) libs.sort(key=lambda lib: lib['stars'], reverse=True) with (THIS_DIR / 'using.toml').open('w') as f: for lib in libs: f.write('[[libs]]\nrepo = "{repo}"\nstars = {stars}\n'.format(**lib)) pydantic-pydantic-ba0aa01/docs/pydantic_people.md000066400000000000000000000026371517143232300222470ustar00rootroot00000000000000# Pydantic People Pydantic has an amazing community of contributors, reviewers, and experts that help propel the project forward. Here, we celebrate those people and their contributions. ## Maintainers These are the current maintainers of the Pydantic repository. Feel free to tag us if you have questions, review requests, or feature requests for which you'd like feedback! {{ maintainers }} ## Experts These are the users that have helped others the most with questions in GitHub through *all time*. {{ experts }} ### Most active users last month These are the users that have helped others the most with questions in GitHub during the last month. {{ most_active_users }} ## Top contributors These are the users that have created the most pull requests that have been *merged*. {{ top_contributors }} ## Top Reviewers These are the users that have reviewed the most Pull Requests from others, assisting with code quality, documentation, bug fixes, feature requests, etc. {{ top_reviewers }} ## About the data The data displayed above is calculated monthly via the Github GraphQL API (see [source code](https://github.com/pydantic/pydantic/tree/main/.github/actions/people/people.py), many thanks to [Sebastián Ramírez](https://github.com/tiangolo) for the script from which we based this logic). Depending on changing conditions, the thresholds for the different categories of contributors may change in the future. pydantic-pydantic-ba0aa01/docs/theme/000077500000000000000000000000001517143232300176405ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/docs/theme/announce.html000066400000000000000000000010711517143232300223330ustar00rootroot00000000000000 What's new — we've launched Pydantic Logfire 🔥 to help you monitor and understand your Pydantic validations. pydantic-pydantic-ba0aa01/docs/theme/main.html000066400000000000000000000005011517143232300214460ustar00rootroot00000000000000{% extends "base.html" %} {% block announce %} {% include 'announce.html' ignore missing %} {% endblock %} {% block content %} {{ super() }} {% include 'mkdocs_run_deps.html' ignore missing %} {% endblock %} pydantic-pydantic-ba0aa01/docs/theme/partials/000077500000000000000000000000001517143232300214575ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/docs/theme/partials/search.html000066400000000000000000000034131517143232300236130ustar00rootroot00000000000000 pydantic-pydantic-ba0aa01/docs/version-policy.md000066400000000000000000000135311517143232300220450ustar00rootroot00000000000000First of all, we recognize that the transitions from Pydantic V1 to V2 has been and will be painful for some users. We're sorry about this pain :pray:, it was an unfortunate but necessary step to correct design mistakes of V1. **There will not be another breaking change of this magnitude!** ## Pydantic V1 Active development of V1 has already stopped, however critical bug fixes and security vulnerabilities will be fixed in V1 until the release of Pydantic V3. ## Pydantic V2 We will not intentionally make breaking changes in minor releases of V2. Functionality marked as deprecated will not be removed until the next major V3 release. Of course, some apparently safe changes and bug fixes will inevitably break some users' code — obligatory link to [xkcd](https://xkcd.com/1172/). The following changes will **NOT** be considered breaking changes, and may occur in minor releases: * Bug fixes that may result in existing code breaking, provided that such code was relying on undocumented features/constructs. * Changing the format of JSON Schema [references](https://json-schema.org/understanding-json-schema/structuring#dollarref). * Changing the `msg`, `ctx`, and `loc` fields of [`ValidationError`][pydantic_core.ValidationError] exceptions. `type` will not change — if you're programmatically parsing error messages, you should use `type`. * Adding new keys to [`ValidationError`][pydantic_core.ValidationError] exceptions — e.g. we intend to add `line_number` and `column_number` to errors when validating JSON once we migrate to a new JSON parser. * Adding new [`ValidationError`][pydantic_core.ValidationError] errors. * Changing how `__repr__` behaves, even of public classes. * The contents of the [core schemas](./internals/architecture.md#communicating-between-pydantic-and-pydantic-core-the-core-schema) (usually available under the [`__pydantic_core_schema__`][pydantic.BaseModel.__pydantic_core_schema__] attribute for Pydantic models and `core_schema` for [type adapters](./concepts/type_adapter.md)) may change between releases (this is a low-level format Pydantic uses to plan how to execute validation and serialization). In all cases we will aim to minimize churn and do so only when justified by the increase of quality of Pydantic for users. ## Pydantic V3 and beyond We expect to make new major releases roughly once a year going forward, although as mentioned above, any associated breaking changes should be trivial to fix compared to the V1-to-V2 transition. ## Experimental Features At Pydantic, we like to move quickly and innovate! To that end, we may introduce experimental features in minor releases. !!! abstract "Usage Documentation" To learn more about our current experimental features, see the [experimental features documentation](./concepts/experimental.md). Please keep in mind, experimental features are active works in progress. If these features are successful, they'll eventually become part of Pydantic. If unsuccessful, said features will be removed with little notice. While in its experimental phase, a feature's API and behaviors may not be stable, and it's very possible that changes made to the feature will not be backward-compatible. ### Naming Conventions We use one of the following naming conventions to indicate that a feature is experimental: 1. The feature is located in the [`experimental`](api/experimental.md) module. In this case, you can access the feature like this: ```python {test="skip" lint="skip"} from pydantic.experimental import feature_name ``` 2. The feature is located in the main module, but prefixed with `experimental_`. This case occurs when we add a new field, argument, or method to an existing data structure already within the main `pydantic` module. New features with these naming conventions are subject to change or removal, and we are looking for feedback and suggestions before making them a permanent part of Pydantic. See the [feedback section](./concepts/experimental.md#feedback) for more information. ### Lifecycle of Experimental Features 1. A new feature is added, either in the [`experimental`](api/experimental.md) module or with the `experimental_` prefix. 2. The behavior is often modified during patch/minor releases, with potential API/behavior changes. 3. If the feature is successful, we promote it to Pydantic with the following steps: a. If it was in the [`experimental`](api/experimental.md) module, the feature is cloned to Pydantic's main module. The original experimental feature still remains in the [`experimental`](api/experimental.md) module, but it will show a warning when used. If the feature was already in the main Pydantic module, we create a copy of the feature without the `experimental_` prefix, so the feature exists with both the official and experimental names. A deprecation warning is attached to the experimental version. b. At some point, the code of the experimental feature is removed, but there will still be a stub of the feature that provides an error message with appropriate instructions. c. As a last step, the experimental version of the feature is entirely removed from the codebase. If the feature is unsuccessful or unpopular, it's removed with little notice. A stub will remain in the location of the deprecated feature with an error message. Thanks to [streamlit](https://docs.streamlit.io/develop/quick-reference/prerelease) for the inspiration for the lifecycle and naming conventions of our new experimental feature patterns. ## Support for Python versions Pydantic will drop support for a Python version when the following conditions are met: * The Python version has reached its [expected end of life](https://devguide.python.org/versions/). * less than 5% of downloads of the most recent minor release are using that version. pydantic-pydantic-ba0aa01/docs/why.md000066400000000000000000000352401517143232300176730ustar00rootroot00000000000000# Why use Pydantic Validation? Today, Pydantic is downloaded many times a month and used by some of the largest and most recognisable organisations in the world. It's hard to know why so many people have adopted Pydantic since its inception six years ago, but here are a few guesses. ## Type hints powering schema validation {#type-hints} The schema that Pydantic validates against is generally defined by Python [type hints](https://docs.python.org/3/glossary.html#term-type-hint). Type hints are great for this since, if you're writing modern Python, you already know how to use them. Using type hints also means that Pydantic integrates well with static typing tools (like [mypy](https://www.mypy-lang.org/) and [Pyright](https://github.com/microsoft/pyright/)) and IDEs (like [PyCharm](https://www.jetbrains.com/pycharm/) and [VSCode](https://code.visualstudio.com/)). ???+ example "Example - just type hints" ```python from typing import Annotated, Literal from annotated_types import Gt from pydantic import BaseModel class Fruit(BaseModel): name: str # (1)! color: Literal['red', 'green'] # (2)! weight: Annotated[float, Gt(0)] # (3)! bazam: dict[str, list[tuple[int, bool, float]]] # (4)! print( Fruit( name='Apple', color='red', weight=4.2, bazam={'foobar': [(1, True, 0.1)]}, ) ) #> name='Apple' color='red' weight=4.2 bazam={'foobar': [(1, True, 0.1)]} ``` 1. The `name` field is simply annotated with `str` — any string is allowed. 2. The [`Literal`][typing.Literal] type is used to enforce that `color` is either `'red'` or `'green'`. 3. Even when we want to apply constraints not encapsulated in Python types, we can use [`Annotated`][typing.Annotated] and [`annotated-types`](https://github.com/annotated-types/annotated-types) to enforce constraints while still keeping typing support. 4. I'm not claiming "bazam" is really an attribute of fruit, but rather to show that arbitrarily complex types can easily be validated. !!! tip "Learn more" See the [documentation on supported types](concepts/types.md). ## Performance Pydantic's core validation logic is implemented in a separate package ([`pydantic-core`](https://pypi.org/project/pydantic-core)), where validation for most types is implemented in Rust. As a result, Pydantic is among the fastest data validation libraries for Python. ??? example "Performance Example - Pydantic vs. dedicated code" In general, dedicated code should be much faster than a general-purpose validator, but in this example Pydantic is >300% faster than dedicated code when parsing JSON and validating URLs. ```python {title="Performance Example" test="skip"} import json import timeit from urllib.parse import urlparse import requests from pydantic import HttpUrl, TypeAdapter reps = 7 number = 100 r = requests.get('https://api.github.com/emojis') r.raise_for_status() emojis_json = r.content def emojis_pure_python(raw_data): data = json.loads(raw_data) output = {} for key, value in data.items(): assert isinstance(key, str) url = urlparse(value) assert url.scheme in ('https', 'http') output[key] = url emojis_pure_python_times = timeit.repeat( 'emojis_pure_python(emojis_json)', globals={ 'emojis_pure_python': emojis_pure_python, 'emojis_json': emojis_json, }, repeat=reps, number=number, ) print(f'pure python: {min(emojis_pure_python_times) / number * 1000:0.2f}ms') #> pure python: 5.32ms type_adapter = TypeAdapter(dict[str, HttpUrl]) emojis_pydantic_times = timeit.repeat( 'type_adapter.validate_json(emojis_json)', globals={ 'type_adapter': type_adapter, 'HttpUrl': HttpUrl, 'emojis_json': emojis_json, }, repeat=reps, number=number, ) print(f'pydantic: {min(emojis_pydantic_times) / number * 1000:0.2f}ms') #> pydantic: 1.54ms print( f'Pydantic {min(emojis_pure_python_times) / min(emojis_pydantic_times):0.2f}x faster' ) #> Pydantic 3.45x faster ``` Unlike other performance-centric libraries written in compiled languages, Pydantic also has excellent support for customizing validation via [functional validators](#customisation). !!! tip "Learn more" Samuel Colvin's [talk at PyCon 2023](https://youtu.be/pWZw7hYoRVU) explains how [`pydantic-core`](https://pypi.org/project/pydantic-core) works and how it integrates with Pydantic. ## Serialization Pydantic provides functionality to serialize model in three ways: 1. To a Python `dict` made up of the associated Python objects. 2. To a Python `dict` made up only of "jsonable" types. 3. To a JSON string. In all three modes, the output can be customized by excluding specific fields, excluding unset fields, excluding default values, and excluding `None` values. ??? example "Example - Serialization 3 ways" ```python from datetime import datetime from pydantic import BaseModel class Meeting(BaseModel): when: datetime where: bytes why: str = 'No idea' m = Meeting(when='2020-01-01T12:00', where='home') print(m.model_dump(exclude_unset=True)) #> {'when': datetime.datetime(2020, 1, 1, 12, 0), 'where': b'home'} print(m.model_dump(exclude={'where'}, mode='json')) #> {'when': '2020-01-01T12:00:00', 'why': 'No idea'} print(m.model_dump_json(exclude_defaults=True)) #> {"when":"2020-01-01T12:00:00","where":"home"} ``` !!! tip "Learn more" See the [documentation on serialization](concepts/serialization.md). ## JSON Schema A [JSON Schema](https://json-schema.org/) can be generated for any Pydantic schema — allowing self-documenting APIs and integration with a wide variety of tools which support the JSON Schema format. ??? example "Example - JSON Schema" ```python from datetime import datetime from pydantic import BaseModel class Address(BaseModel): street: str city: str zipcode: str class Meeting(BaseModel): when: datetime where: Address why: str = 'No idea' print(Meeting.model_json_schema()) """ { '$defs': { 'Address': { 'properties': { 'street': {'title': 'Street', 'type': 'string'}, 'city': {'title': 'City', 'type': 'string'}, 'zipcode': {'title': 'Zipcode', 'type': 'string'}, }, 'required': ['street', 'city', 'zipcode'], 'title': 'Address', 'type': 'object', } }, 'properties': { 'when': {'format': 'date-time', 'title': 'When', 'type': 'string'}, 'where': {'$ref': '#/$defs/Address'}, 'why': {'default': 'No idea', 'title': 'Why', 'type': 'string'}, }, 'required': ['when', 'where'], 'title': 'Meeting', 'type': 'object', } """ ``` Pydantic is compliant with the latest version of JSON Schema specification ([2020-12](https://json-schema.org/draft/2020-12/release-notes.html)), which is compatible with [OpenAPI 3.1](https://spec.openapis.org/oas/v3.1.0.html). !!! tip "Learn more" See the [documentation on JSON Schema](concepts/json_schema.md). ## Strict mode and data coercion {#strict-lax} By default, Pydantic is tolerant to common incorrect types and coerces data to the right type — e.g. a numeric string passed to an `int` field will be parsed as an `int`. Pydantic also has as [strict mode](concepts/strict_mode.md), where types are not coerced and a validation error is raised unless the input data exactly matches the expected schema. But strict mode would be pretty useless when validating JSON data since JSON doesn't have types matching many common Python types like [`datetime`][datetime.datetime], [`UUID`][uuid.UUID] or [`bytes`][]. To solve this, Pydantic can parse and validate JSON in one step. This allows sensible data conversion (e.g. when parsing strings into [`datetime`][datetime.datetime] objects). Since the JSON parsing is implemented in Rust, it's also very performant. ??? example "Example - Strict mode that's actually useful" ```python from datetime import datetime from pydantic import BaseModel, ValidationError class Meeting(BaseModel): when: datetime where: bytes m = Meeting.model_validate({'when': '2020-01-01T12:00', 'where': 'home'}) print(m) #> when=datetime.datetime(2020, 1, 1, 12, 0) where=b'home' try: m = Meeting.model_validate( {'when': '2020-01-01T12:00', 'where': 'home'}, strict=True ) except ValidationError as e: print(e) """ 2 validation errors for Meeting when Input should be a valid datetime [type=datetime_type, input_value='2020-01-01T12:00', input_type=str] where Input should be a valid bytes [type=bytes_type, input_value='home', input_type=str] """ m_json = Meeting.model_validate_json( '{"when": "2020-01-01T12:00", "where": "home"}' ) print(m_json) #> when=datetime.datetime(2020, 1, 1, 12, 0) where=b'home' ``` !!! tip "Learn more" See the [documentation on strict mode](concepts/strict_mode.md). ## Dataclasses, TypedDicts, and more {#dataclasses-typeddict-more} Pydantic provides four ways to create schemas and perform validation and serialization: 1. [`BaseModel`](concepts/models.md) — Pydantic's own super class with many common utilities available via instance methods. 2. [Pydantic dataclasses](concepts/dataclasses.md) — a wrapper around standard dataclasses with additional validation performed. 3. [`TypeAdapter`][pydantic.type_adapter.TypeAdapter] — a general way to adapt any type for validation and serialization. This allows types like [`TypedDict`](api/standard_library_types.md#typeddict) and [`NamedTuple`](api/standard_library_types.md#named-tuples) to be validated as well as simple types (like [`int`][] or [`timedelta`][datetime.timedelta]) — [all types](concepts/types.md) supported can be used with [`TypeAdapter`][pydantic.type_adapter.TypeAdapter]. 4. [`validate_call`](concepts/validation_decorator.md) — a decorator to perform validation when calling a function. ??? example "Example - schema based on a [`TypedDict`][typing.TypedDict]" ```python from datetime import datetime from typing_extensions import NotRequired, TypedDict from pydantic import TypeAdapter class Meeting(TypedDict): when: datetime where: bytes why: NotRequired[str] meeting_adapter = TypeAdapter(Meeting) m = meeting_adapter.validate_python( # (1)! {'when': '2020-01-01T12:00', 'where': 'home'} ) print(m) #> {'when': datetime.datetime(2020, 1, 1, 12, 0), 'where': b'home'} meeting_adapter.dump_python(m, exclude={'where'}) # (2)! print(meeting_adapter.json_schema()) # (3)! """ { 'properties': { 'when': {'format': 'date-time', 'title': 'When', 'type': 'string'}, 'where': {'format': 'binary', 'title': 'Where', 'type': 'string'}, 'why': {'title': 'Why', 'type': 'string'}, }, 'required': ['when', 'where'], 'title': 'Meeting', 'type': 'object', } """ ``` 1. [`TypeAdapter`][pydantic.type_adapter.TypeAdapter] for a [`TypedDict`][typing.TypedDict] performing validation, it can also validate JSON data directly with [`validate_json`][pydantic.type_adapter.TypeAdapter.validate_json]. 2. [`dump_python`][pydantic.type_adapter.TypeAdapter.dump_python] to serialise a [`TypedDict`][typing.TypedDict] to a python object, it can also serialise to JSON with [`dump_json`][pydantic.type_adapter.TypeAdapter.dump_json]. 3. [`TypeAdapter`][pydantic.type_adapter.TypeAdapter] can also generate a JSON Schema. ## Customisation Functional validators and serializers, as well as a powerful protocol for custom types, means the way Pydantic operates can be customized on a per-field or per-type basis. ??? example "Customisation Example - wrap validators" "wrap validators" are new in Pydantic V2 and are one of the most powerful ways to customize validation. ```python from datetime import datetime, timezone from typing import Any from pydantic_core.core_schema import ValidatorFunctionWrapHandler from pydantic import BaseModel, field_validator class Meeting(BaseModel): when: datetime @field_validator('when', mode='wrap') def when_now( cls, input_value: Any, handler: ValidatorFunctionWrapHandler ) -> datetime: if input_value == 'now': return datetime.now() when = handler(input_value) # in this specific application we know tz naive datetimes are in UTC if when.tzinfo is None: when = when.replace(tzinfo=timezone.utc) return when print(Meeting(when='2020-01-01T12:00+01:00')) #> when=datetime.datetime(2020, 1, 1, 12, 0, tzinfo=TzInfo(3600)) print(Meeting(when='now')) #> when=datetime.datetime(2032, 1, 2, 3, 4, 5, 6) print(Meeting(when='2020-01-01T12:00')) #> when=datetime.datetime(2020, 1, 1, 12, 0, tzinfo=datetime.timezone.utc) ``` !!! tip "Learn more" See the documentation on [validators](concepts/validators.md), [custom serializers](concepts/serialization.md#serializers), and [custom types](concepts/types.md#custom-types). ## Ecosystem At the time of writing there are 466,400 repositories on GitHub and 8,119 packages on PyPI that depend on Pydantic. Some notable libraries that depend on Pydantic: {{ libraries }} More libraries using Pydantic can be found at [`Kludex/awesome-pydantic`](https://github.com/Kludex/awesome-pydantic). ## Organisations using Pydantic {#using-pydantic} Some notable companies and organisations using Pydantic together with comments on why/how we know they're using Pydantic. The organisations below are included because they match one or more of the following criteria: * Using Pydantic as a dependency in a public repository. * Referring traffic to the Pydantic documentation site from an organization-internal domain — specific referrers are not included since they're generally not in the public domain. * Direct communication between the Pydantic team and engineers employed by the organization about usage of Pydantic within the organization. We've included some extra detail where appropriate and already in the public domain. {{ organisations }} pydantic-pydantic-ba0aa01/mkdocs.yml000066400000000000000000000334461517143232300176230ustar00rootroot00000000000000site_name: Pydantic Validation site_description: Data validation using Python type hints strict: true site_url: https://docs.pydantic.dev/ theme: name: 'material' custom_dir: 'docs/theme' palette: - media: '(prefers-color-scheme)' primary: pink accent: pink toggle: icon: material/brightness-auto name: 'Switch to light mode' - media: '(prefers-color-scheme: light)' scheme: default primary: pink accent: pink toggle: icon: material/brightness-7 name: 'Switch to dark mode' - media: '(prefers-color-scheme: dark)' scheme: slate primary: pink accent: pink toggle: icon: material/brightness-4 name: 'Switch to system preference' features: - content.tabs.link - content.code.annotate - content.code.copy - announce.dismiss - navigation.tabs - navigation.instant - navigation.instant.prefetch - navigation.instant.preview - navigation.instant.progress - navigation.path - navigation.sections - navigation.top - navigation.tracking - search.suggest - toc.follow logo: 'logo-white.svg' favicon: 'favicon.png' repo_name: pydantic/pydantic repo_url: https://github.com/pydantic/pydantic edit_uri: edit/main/docs/ extra: version: provider: mike analytics: feedback: title: Was this page helpful? ratings: - icon: material/thumb-up-outline name: This page was helpful data: 1 note: >- Thanks for your feedback! - icon: material/thumb-down-outline name: This page could be improved data: 0 note: >- Thanks for your feedback! # https://www.mkdocs.org/user-guide/configuration/#validation validation: omitted_files: warn absolute_links: warn unrecognized_links: warn anchors: warn extra_css: - 'extra/terminal.css' - 'extra/tweaks.css' extra_javascript: - 'https://cdn.jsdelivr.net/npm/algoliasearch@5.20.0/dist/lite/builds/browser.umd.js' - 'https://cdn.jsdelivr.net/npm/instantsearch.js@4.77.3/dist/instantsearch.production.min.js' - 'extra/algolia.js' - 'extra/feedback.js' - 'extra/fluff.js' - 'extra/mathjax.js' - 'https://samuelcolvin.github.io/mkdocs-run-code/run_code_main.js' - 'https://unpkg.com/mathjax@3/es5/tex-mml-chtml.js' nav: - Get Started: - Welcome to Pydantic: index.md - Why use Pydantic: why.md - Help with Pydantic: help_with_pydantic.md - Installation: install.md - Migration Guide: migration.md - Version Policy: version-policy.md - Contributing: contributing.md - Changelog: changelog.md - Concepts: - Models: concepts/models.md - Fields: concepts/fields.md - JSON Schema: concepts/json_schema.md - JSON: concepts/json.md - Types: concepts/types.md - Unions: concepts/unions.md - Alias: concepts/alias.md - Configuration: concepts/config.md - Serialization: concepts/serialization.md - Validators: concepts/validators.md - Dataclasses: concepts/dataclasses.md - Forward Annotations: concepts/forward_annotations.md - Strict Mode: concepts/strict_mode.md - Type Adapter: concepts/type_adapter.md - Validation Decorator: concepts/validation_decorator.md - Conversion Table: concepts/conversion_table.md - Settings Management: concepts/pydantic_settings.md - Performance: concepts/performance.md - Experimental: concepts/experimental.md - API Documentation: - Pydantic: - BaseModel: api/base_model.md - RootModel: api/root_model.md - Pydantic Dataclasses: api/dataclasses.md - TypeAdapter: api/type_adapter.md - Validate Call: api/validate_call.md - Fields: api/fields.md - Aliases: api/aliases.md - Configuration: api/config.md - JSON Schema: api/json_schema.md - Errors: api/errors.md - Functional Validators: api/functional_validators.md - Functional Serializers: api/functional_serializers.md - Standard Library Types: api/standard_library_types.md - Pydantic Types: api/types.md - Network Types: api/networks.md - Version Information: api/version.md - Annotated Handlers: api/annotated_handlers.md - Experimental: api/experimental.md - Pydantic Core: - pydantic_core: api/pydantic_core.md - pydantic_core.core_schema: api/pydantic_core_schema.md - Pydantic Settings: api/pydantic_settings.md - Pydantic Extra Types: - Color: api/pydantic_extra_types_color.md - Country: api/pydantic_extra_types_country.md - Payment: api/pydantic_extra_types_payment.md - Phone Numbers: api/pydantic_extra_types_phone_numbers.md - Routing Numbers: api/pydantic_extra_types_routing_numbers.md - Coordinate: api/pydantic_extra_types_coordinate.md - Mac Address: api/pydantic_extra_types_mac_address.md - ISBN: api/pydantic_extra_types_isbn.md - Pendulum: api/pydantic_extra_types_pendulum_dt.md - Currency: api/pydantic_extra_types_currency_code.md - Language: api/pydantic_extra_types_language_code.md - Script Code: api/pydantic_extra_types_script_code.md - Semantic Version: api/pydantic_extra_types_semantic_version.md - Timezone Name: api/pydantic_extra_types_timezone_name.md - ULID: api/pydantic_extra_types_ulid.md - Internals: - Architecture: internals/architecture.md - Resolving Annotations: internals/resolving_annotations.md - Examples: - Validating File Data: examples/files.md - Web and API Requests: examples/requests.md - Queues: examples/queues.md - Databases: examples/orms.md - Custom Validators: examples/custom_validators.md - Dynamic models: examples/dynamic_models.md - Agent libraries – Pydantic AI: examples/pydantic_ai.md - Error Messages: - Error Handling: errors/errors.md - Validation Errors: errors/validation_errors.md - Usage Errors: errors/usage_errors.md - Integrations: - Pydantic Logfire: integrations/logfire.md - LLMs: integrations/llms.md - Dev Tools: - Mypy: integrations/mypy.md - Pyrefly: integrations/pyrefly.md - PyCharm: integrations/pycharm.md - Hypothesis: integrations/hypothesis.md - Visual Studio Code: integrations/visual_studio_code.md - datamodel-code-generator: integrations/datamodel_code_generator.md - devtools: integrations/devtools.md - Rich: integrations/rich.md - Linting: integrations/linting.md - Documentation: integrations/documentation.md - Production Tools: - AWS Lambda: integrations/aws_lambda.md - Blog: https://blog.pydantic.dev/ - Pydantic People: pydantic_people.md markdown_extensions: - tables - toc: permalink: true title: Page contents - admonition - pymdownx.details - pymdownx.superfences - pymdownx.highlight: pygments_lang_class: true - pymdownx.extra - pymdownx.emoji: emoji_index: !!python/name:material.extensions.emoji.twemoji emoji_generator: !!python/name:material.extensions.emoji.to_svg - pymdownx.tabbed: alternate_style: true - pymdownx.arithmatex: generic: true - pydantic_docs.mdext watch: - pydantic hooks: - 'docs/plugins/main.py' - 'docs/plugins/algolia.py' plugins: - social - mike: alias_type: symlink canonical_version: latest # llmstxt must come after the mike plugin: - llmstxt: enabled: !ENV [CI, false] full_output: llms-full.txt markdown_description: |- Pydantic is the most widely used data validation library for Python. Fast and extensible, Pydantic plays nicely with your linters/IDE/brain. Define how data should be in pure, canonical Python 3.9+; validate it with Pydantic. sections: Concepts documentation: - concepts/*.md API documentation: - api/*.md Internals: - internals/*.md Optional: - errors/*.md - examples/*.md - integrations/*.md - search - exclude: glob: - theme/announce.html - plugins/* - __pycache__/* - mkdocstrings: handlers: python: paths: [.] # see also: build-docs.sh options: members_order: source separate_signature: true filters: ['!^_'] docstring_options: ignore_init_summary: true merge_init_into_class: true show_signature_annotations: true signature_crossrefs: true import: - url: https://docs.python.org/3/objects.inv domains: [py, std] - url: https://typing-extensions.readthedocs.io/en/latest/objects.inv - redirects: redirect_maps: 'usage/mypy.md': 'integrations/mypy.md' 'mypy_plugin.md': 'integrations/mypy.md' 'datamodel_code_generator.md': 'integrations/datamodel_code_generator.md' 'visual_studio_code.md': 'integrations/visual_studio_code.md' 'hypothesis_plugin.md': 'integrations/hypothesis.md' 'pycharm_plugin.md': 'integrations/pycharm.md' 'usage/model_config.md': 'api/config.md' 'usage/devtools.md': 'integrations/devtools.md' 'usage/rich.md': 'integrations/rich.md' 'usage/linting.md': 'integrations/linting.md' 'usage/types.md': 'concepts/types.md' 'usage/types/secrets.md': 'api/types.md#pydantic.types.Secret' 'usage/types/string_types.md': 'api/types.md#pydantic.types.StringConstraints' 'usage/types/file_types.md': 'api/types.md#pydantic.types.FilePath' 'api/main.md': 'api/base_model.md' 'api/color.md': 'api/pydantic_extra_types_color.md' 'api/alias_generators.md': 'api/config.md#pydantic.config.ConfigDict.alias_generator' 'api/pydantic_core_init.md': 'api/pydantic_core.md' 'usage/types/booleans.md': 'api/standard_library_types.md#booleans' 'usage/types/callables.md': 'api/standard_library_types.md#callable' 'usage/types/custom.md': 'concepts/types.md#custom-types' 'usage/types/datetime.md': 'api/standard_library_types.md#datetime-types' 'usage/types/enum.md': 'api/standard_library_types.md#enum' 'usage/types/json.md': 'api/types.md#pydantic.types.Json' 'usage/types/list_types.md': 'api/standard_library_types.md#list' 'usage/types/standard_types.md': 'api/standard_library_types.md' 'usage/types/strict_types.md': 'concepts/types.md#strict-types' 'usage/types/types.md': 'concepts/types.md' 'usage/types/urls.md': 'api/networks.md' 'usage/types/unions.md': 'api/standard_library_types.md#union' 'usage/types/typevars.md': 'api/standard_library_types.md#type-and-typevar' 'usage/types/types_fields.md': 'api/standard_library_types.md' 'usage/validation_errors.md': 'errors/validation_errors.md' 'usage/errors.md': 'errors/usage_errors.md' 'usage/types/extra_types/color_types.md': 'api/pydantic_extra_types_color.md' 'usage/types/extra_types/extra_types.md': 'api/pydantic_extra_types_color.md' 'usage/types/extra_types/coordinate.md': 'api/pydantic_extra_types_coordinate.md' 'usage/types/extra_types/mac_address.md': 'api/pydantic_extra_types_mac_address.md' 'usage/types/extra_types/payment_cards.md': 'api/pydantic_extra_types_payment.md' 'usage/types/extra_types/phone_numbers.md': 'api/pydantic_extra_types_phone_numbers.md' 'usage/types/extra_types/routing_numbers.md': 'api/pydantic_extra_types_routing_numbers.md' 'version-compatibility.md': 'version-policy.md' 'api/pydantic_extra_types_routing_number.md': 'api/pydantic_extra_types_routing_numbers.md' 'usage/computed_fields.md': 'api/fields.md#pydantic.fields.computed_field' 'usage/conversion_table.md': 'concepts/conversion_table.md' 'usage/dataclasses.md': 'concepts/dataclasses.md' 'usage/fields.md': 'concepts/fields.md' 'usage/json_schema.md': 'concepts/json_schema.md' 'usage/models.md': 'concepts/models.md' 'usage/postponed_annotations.md': 'concepts/forward_annotations.md' 'concepts/postponed_annotations.md': 'concepts/forward_annotations.md' 'usage/pydantic_settings.md': 'concepts/pydantic_settings.md' 'usage/serialization.md': 'concepts/serialization.md' 'usage/strict_mode.md': 'concepts/strict_mode.md' 'usage/type_adapter.md': 'concepts/type_adapter.md' 'usage/validation_decorator.md': 'concepts/validation_decorator.md' 'usage/validators.md': 'concepts/validators.md' 'usage/types/bytesize.md': 'api/types.md#pydantic.types.ByteSize' 'usage/types/dicts_mapping.md': 'api/standard_library_types.md#mapping-types' 'usage/types/encoded.md': 'api/types.md#pydantic.types.EncodedBytes' 'usage/types/enums.md': 'api/standard_library_types.md#enum' 'usage/types/number_types.md': 'api/standard_library_types.md#number-types' 'usage/types/sequence_iterable.md': 'api/standard_library_types.md#other-iterables' 'usage/types/set_types.md': 'api/standard_library_types.md#sets' 'usage/types/uuids.md': 'api/standard_library_types.md#uuid' 'blog/pydantic-v2-alpha.md': 'https://pydantic.dev/articles/pydantic-v2-alpha' 'blog/pydantic-v2-final.md': 'https://pydantic.dev/articles/pydantic-v2-final' 'blog/pydantic-v2.md': 'https://pydantic.dev/articles/pydantic-v2' 'examples/secrets.md': 'api/types.md#pydantic.types.Secret' 'examples/validators.md': 'examples/custom_validators.md' 'architecture.md': 'internals/architecture.md' pydantic-pydantic-ba0aa01/pydantic-core/000077500000000000000000000000001517143232300203475ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/pydantic-core/.cargo/000077500000000000000000000000001517143232300215205ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/pydantic-core/.cargo/config.toml000066400000000000000000000004701517143232300236630ustar00rootroot00000000000000[build] rustflags = [] # see https://pyo3.rs/main/building_and_distribution.html#macos [target.x86_64-apple-darwin] rustflags = [ "-C", "link-arg=-undefined", "-C", "link-arg=dynamic_lookup", ] [target.aarch64-apple-darwin] rustflags = [ "-C", "link-arg=-undefined", "-C", "link-arg=dynamic_lookup", ] pydantic-pydantic-ba0aa01/pydantic-core/.codecov.yml000066400000000000000000000002711517143232300225720ustar00rootroot00000000000000codecov: require_ci_to_pass: false coverage: precision: 2 range: [90, 100] status: patch: false project: false comment: layout: 'header, diff, flags, files, footer' pydantic-pydantic-ba0aa01/pydantic-core/.gitignore000066400000000000000000000006031517143232300223360ustar00rootroot00000000000000*.py[cod] *.egg-info/ .coverage .python-version package-lock.json test.py .cache/ .hypothesis/ build/ dist/ docs/_build/ htmlcov/ node_modules/ /.benchmarks/ /.idea/ /.pytest_cache/ /.vscode/ /env*/ /env/ /flame/ /pytest-speed/ /sandbox/ /sandbox/ /site/ /target/ /worktree/ /.editorconfig /*.lcov /*.profdata /*.profraw /foobar.py /python/pydantic_core/*.so # samply /profile.json pydantic-pydantic-ba0aa01/pydantic-core/.mypy-stubtest-allowlist000066400000000000000000000011061517143232300252270ustar00rootroot00000000000000# TODO: don't want to expose this staticmethod, requires https://github.com/PyO3/pyo3/issues/2384 pydantic_core._pydantic_core.PydanticUndefinedType.new # See #1540 for discussion pydantic_core._pydantic_core.from_json pydantic_core._pydantic_core.SchemaValidator.validate_python pydantic_core._pydantic_core.SchemaValidator.validate_json pydantic_core._pydantic_core.SchemaValidator.validate_strings # the `warnings` kwarg for SchemaSerializer functions has custom logic pydantic_core._pydantic_core.SchemaSerializer.to_python pydantic_core._pydantic_core.SchemaSerializer.to_json pydantic-pydantic-ba0aa01/pydantic-core/.pre-commit-config.yaml000066400000000000000000000013711517143232300246320ustar00rootroot00000000000000fail_fast: true repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.0.1 hooks: - id: check-yaml - id: check-toml - id: end-of-file-fixer - id: trailing-whitespace - id: check-added-large-files - repo: local hooks: - id: lint-python name: Lint Python entry: make lint-python types: [python] language: system pass_filenames: false - id: typecheck-python name: Typecheck Python entry: make pyright types: [python] language: system pass_filenames: false - id: lint-rust name: Lint Rust entry: make lint-rust types: [rust] language: system pass_filenames: false pydantic-pydantic-ba0aa01/pydantic-core/.rustfmt.toml000066400000000000000000000000201517143232300230160ustar00rootroot00000000000000max_width = 120 pydantic-pydantic-ba0aa01/pydantic-core/Cargo.lock000066400000000000000000000602271517143232300222630ustar00rootroot00000000000000# This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "ahash" version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", "getrandom", "once_cell", "version_check", "zerocopy", ] [[package]] name = "aho-corasick" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "allocator-api2" version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "autocfg" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitflags" version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "bitvec" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ "funty", "radium", "tap", "wyz", ] [[package]] name = "bumpalo" version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cc" version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac367972e516d45567c7eafc73d24e1c193dcf200a8d94e9db7b3d38b349572d" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "displaydoc" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "enum_dispatch" version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa18ce2bc66555b3218614519ac839ddb759a7d6720732f979ef8d13be147ecd" dependencies = [ "once_cell", "proc-macro2", "quote", "syn", ] [[package]] name = "equivalent" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "foldhash" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" [[package]] name = "form_urlencoded" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] [[package]] name = "funty" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "getrandom" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", "r-efi", "wasi", ] [[package]] name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ "allocator-api2", "equivalent", "foldhash", ] [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "icu_collections" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" dependencies = [ "displaydoc", "yoke", "zerofrom", "zerovec", ] [[package]] name = "icu_locid" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" dependencies = [ "displaydoc", "litemap", "tinystr", "writeable", "zerovec", ] [[package]] name = "icu_locid_transform" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" dependencies = [ "displaydoc", "icu_locid", "icu_locid_transform_data", "icu_provider", "tinystr", "zerovec", ] [[package]] name = "icu_locid_transform_data" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" [[package]] name = "icu_normalizer" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" dependencies = [ "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", "icu_provider", "smallvec", "utf16_iter", "utf8_iter", "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" [[package]] name = "icu_properties" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" dependencies = [ "displaydoc", "icu_collections", "icu_locid_transform", "icu_properties_data", "icu_provider", "tinystr", "zerovec", ] [[package]] name = "icu_properties_data" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" [[package]] name = "icu_provider" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" dependencies = [ "displaydoc", "icu_locid", "icu_provider_macros", "stable_deref_trait", "tinystr", "writeable", "yoke", "zerofrom", "zerovec", ] [[package]] name = "icu_provider_macros" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "idna" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", "utf8_iter", ] [[package]] name = "idna_adapter" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" dependencies = [ "icu_normalizer", "icu_properties", ] [[package]] name = "itoa" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jiter" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6f3b5d3f84b36f4ad09fd1da896d23d9852a1aa86556578dd0289f43dce311d" dependencies = [ "ahash", "bitvec", "lexical-parse-float", "num-bigint", "num-traits", "pyo3", "pyo3-build-config", "smallvec", ] [[package]] name = "js-sys" version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ "once_cell", "wasm-bindgen", ] [[package]] name = "lexical-parse-float" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de6f9cb01fb0b08060209a057c048fcbab8717b4c1ecd2eac66ebfe39a65b0f2" dependencies = [ "lexical-parse-integer", "lexical-util", "static_assertions", ] [[package]] name = "lexical-parse-integer" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72207aae22fc0a121ba7b6d479e42cbfea549af1479c3f3a4f12c70dd66df12e" dependencies = [ "lexical-util", "static_assertions", ] [[package]] name = "lexical-util" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a82e24bf537fd24c177ffbbdc6ebcc8d54732c35b50a3f28cc3f4e4c949a0b3" dependencies = [ "static_assertions", ] [[package]] name = "libc" version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "litemap" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" [[package]] name = "log" version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "lru" version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593" dependencies = [ "hashbrown", ] [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "num-bigint" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", ] [[package]] name = "num-integer" version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ "num-traits", ] [[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "once_cell" version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "percent-encoding" version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "portable-atomic" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" [[package]] name = "proc-macro2" version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "pydantic-core" version = "2.46.3" dependencies = [ "ahash", "base64", "enum_dispatch", "hashbrown", "hex", "idna", "jiter", "lru", "num-bigint", "num-traits", "percent-encoding", "pyo3", "pyo3-build-config", "regex", "serde", "serde_json", "smallvec", "speedate", "strum", "strum_macros", "url", "uuid", "version_check", ] [[package]] name = "pyo3" version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91fd8e38a3b50ed1167fb981cd6fd60147e091784c427b8f7183a7ee32c31c12" dependencies = [ "libc", "num-bigint", "num-traits", "once_cell", "portable-atomic", "pyo3-build-config", "pyo3-ffi", "pyo3-macros", "smallvec", ] [[package]] name = "pyo3-build-config" version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e368e7ddfdeb98c9bca7f8383be1648fd84ab466bf2bc015e94008db6d35611e" dependencies = [ "python3-dll-a", "target-lexicon", ] [[package]] name = "pyo3-ffi" version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f29e10af80b1f7ccaf7f69eace800a03ecd13e883acfacc1e5d0988605f651e" dependencies = [ "libc", "pyo3-build-config", ] [[package]] name = "pyo3-macros" version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df6e520eff47c45997d2fc7dd8214b25dd1310918bbb2642156ef66a67f29813" dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", "syn", ] [[package]] name = "pyo3-macros-backend" version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4cdc218d835738f81c2338f822078af45b4afdf8b2e33cbb5916f108b813acb" dependencies = [ "heck", "proc-macro2", "pyo3-build-config", "quote", "syn", ] [[package]] name = "python3-dll-a" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d381ef313ae70b4da5f95f8a4de773c6aa5cd28f73adec4b4a31df70b66780d8" dependencies = [ "cc", ] [[package]] name = "quote" version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] [[package]] name = "r-efi" version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" [[package]] name = "radium" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "regex" version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rustversion" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "serde" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", ] [[package]] name = "serde_core" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", "serde", "serde_core", "zmij", ] [[package]] name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "speedate" version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aba069c070b5e213f2a094deb7e5ed50ecb092be36102a4f4042e8d2056d060e" dependencies = [ "lexical-parse-float", "strum", "strum_macros", ] [[package]] name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "strum" version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" dependencies = [ "heck", "proc-macro2", "quote", "syn", ] [[package]] name = "syn" version = "2.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "synstructure" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "tap" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "target-lexicon" version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1dd07eb858a2067e2f3c7155d54e929265c264e6f37efe3ee7a8d1b5a1dd0ba" [[package]] name = "tinystr" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ "displaydoc", "zerovec", ] [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "url" version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", "percent-encoding", "serde", ] [[package]] name = "utf16_iter" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" [[package]] name = "utf8_iter" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" version = "1.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wasi" version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" dependencies = [ "wit-bindgen-rt", ] [[package]] name = "wasm-bindgen" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" dependencies = [ "unicode-ident", ] [[package]] name = "wit-bindgen-rt" version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ "bitflags", ] [[package]] name = "write16" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" [[package]] name = "writeable" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" [[package]] name = "wyz" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" dependencies = [ "tap", ] [[package]] name = "yoke" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" dependencies = [ "serde", "stable_deref_trait", "yoke-derive", "zerofrom", ] [[package]] name = "yoke-derive" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" dependencies = [ "proc-macro2", "quote", "syn", "synstructure", ] [[package]] name = "zerocopy" version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "zerofrom" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" dependencies = [ "proc-macro2", "quote", "syn", "synstructure", ] [[package]] name = "zerovec" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" dependencies = [ "yoke", "zerofrom", "zerovec-derive", ] [[package]] name = "zerovec-derive" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "zmij" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aac060176f7020d62c3bcc1cdbcec619d54f48b07ad1963a3f80ce7a0c17755f" pydantic-pydantic-ba0aa01/pydantic-core/Cargo.toml000066400000000000000000000054731517143232300223100ustar00rootroot00000000000000[package] name = "pydantic-core" version = "2.46.3" edition = "2024" license = "MIT" homepage = "https://github.com/pydantic/pydantic" repository = "https://github.com/pydantic/pydantic.git" readme = "README.md" include = [ "/pyproject.toml", "/README.md", "/LICENSE", "/Makefile", "/build.rs", "/rust-toolchain", "/src", "/python/pydantic_core", "/tests", "/.cargo", "!__pycache__", "!tests/.hypothesis", "!tests/.pytest_cache", "!*.so", ] rust-version = "1.88" [dependencies] # TODO it would be very nice to remove the "py-clone" feature as it can panic, # but needs a bit of work to make sure it's not used in the codebase pyo3 = { version = "0.28", features = ["generate-import-lib", "num-bigint", "py-clone", "smallvec"] } regex = "1.12.3" lru = "0.16.3" strum = { version = "0.27", features = ["derive"] } strum_macros = "0.27" serde_json = { version = "1.0.149", features = ["arbitrary_precision"] } enum_dispatch = "0.3.13" serde = { version = "1.0.219", features = ["derive"] } speedate = "0.17.0" smallvec = "1.15.1" ahash = "0.8.12" url = "2.5.8" # idna is already required by url, added here to be explicit idna = "1.1.0" base64 = "0.22.1" num-bigint = "0.4.6" num-traits = "0.2.19" uuid = "1.23.0" jiter = { version = "0.14.0", features = ["python"] } hex = "0.4.3" percent-encoding = "2.3.2" hashbrown = { version = "0.16", default-features = false, features = ["inline-more"] } [lib] name = "_pydantic_core" crate-type = ["cdylib", "rlib"] [profile.release] lto = "fat" codegen-units = 1 strip = true [profile.bench] debug = true strip = false # This is separate to benchmarks because `bench` ends up building testing # harnesses into code, as it's a special cargo profile. [profile.profiling] inherits = "release" debug = true strip = false [dev-dependencies] pyo3 = { version = "0.28", features = ["auto-initialize"] } [build-dependencies] version_check = "0.9.5" # used where logic has to be version/distribution specific, e.g. pypy pyo3-build-config = { version = "0.28" } [lints.clippy] dbg_macro = "warn" print_stdout = "warn" # in general we lint against the pedantic group, but we will whitelist # certain lints which we don't want to enforce (for now) pedantic = { level = "warn", priority = -1 } cast_possible_truncation = "allow" cast_possible_wrap = "allow" cast_precision_loss = "allow" cast_sign_loss = "allow" doc_markdown = "allow" float_cmp = "allow" fn_params_excessive_bools = "allow" if_not_else = "allow" match_bool = "allow" missing_errors_doc = "allow" missing_panics_doc = "allow" module_name_repetitions = "allow" must_use_candidate = "allow" needless_pass_by_value = "allow" similar_names = "allow" single_match_else = "allow" struct_excessive_bools = "allow" too_many_lines = "allow" unnecessary_wraps = "allow" unused_self = "allow" used_underscore_binding = "allow" pydantic-pydantic-ba0aa01/pydantic-core/LICENSE000066400000000000000000000020701517143232300213530ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2022 Samuel Colvin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. pydantic-pydantic-ba0aa01/pydantic-core/Makefile000066400000000000000000000111171517143232300220100ustar00rootroot00000000000000.DEFAULT_GOAL := all sources = python/pydantic_core tests wasm-preview/run_tests.py mypy-stubtest = uv run python -m mypy.stubtest pydantic_core._pydantic_core --allowlist .mypy-stubtest-allowlist # using --no-sync to avoid uv automatically rebuilding pydantic-core # TODO: it might be nice to use `MATURIN_PEP517_ARGS` to set the profile and # then use uv directly, but probably want # https://github.com/astral-sh/uv/issues/16359 first uv-run-no-sync = uv run --no-sync # using pip install cargo (via maturin via pip) doesn't get the tty handle # so doesn't render color without some help export CARGO_TERM_COLOR=$(shell (test -t 0 && echo "always") || echo "auto") .PHONY: .uv ## Check that uv is installed .uv: @uv -V || echo 'Please install uv: https://docs.astral.sh/uv/getting-started/installation/' .PHONY: install ## Install the package, dependencies, and pre-commit for local development install: .uv uv sync --frozen --all-groups uv run pre-commit install --install-hooks .PHONY: rebuild-lockfiles ## Rebuild lockfiles from scratch, updating all dependencies rebuild-lockfiles: .uv uv lock --upgrade .PHONY: install-rust-coverage ## Install Rust coverage tools install-rust-coverage: cargo install rustfilt coverage-prepare rustup component add llvm-tools-preview .PHONY: install-pgo ## Install Rust PGO tools install-pgo: rustup component add llvm-tools-preview .PHONY: build-dev ## Build the development version of the package build-dev: @rm -f python/pydantic_core/*.so $(uv-run-no-sync) maturin develop --uv .PHONY: build-prod ## Build the production version of the package build-prod: @rm -f python/pydantic_core/*.so $(uv-run-no-sync) maturin develop --uv --release .PHONY: build-profiling ## Build the profiling version of the package build-profiling: @rm -f python/pydantic_core/*.so $(uv-run-no-sync) maturin develop --uv --profile profiling .PHONY: build-coverage ## Build the coverage version of the package build-coverage: @rm -f python/pydantic_core/*.so RUSTFLAGS='-C instrument-coverage' $(uv-run-no-sync) maturin develop --uv --release .PHONY: build-pgo ## Build the PGO version of the package build-pgo: @rm -f python/pydantic_core/*.so $(eval PROFDATA := $(shell mktemp -d)) RUSTFLAGS='-Cprofile-generate=$(PROFDATA)' $(uv-run-no-sync) maturin develop --uv --release $(uv-run-no-sync) pytest tests/benchmarks $(eval LLVM_PROFDATA := $(shell rustup run stable bash -c 'echo $$RUSTUP_HOME/toolchains/$$RUSTUP_TOOLCHAIN/lib/rustlib/$$(rustc -Vv | grep host | cut -d " " -f 2)/bin/llvm-profdata')) $(LLVM_PROFDATA) merge -o $(PROFDATA)/merged.profdata $(PROFDATA) RUSTFLAGS='-Cprofile-use=$(PROFDATA)/merged.profdata' $(uv-run-no-sync) maturin develop --uv --release @rm -rf $(PROFDATA) .PHONY: build-wasm ## Build the WebAssembly version of the package build-wasm: @echo 'This requires python 3.13, maturin and emsdk to be installed' uvx maturin build --release --target wasm32-unknown-emscripten --out dist -i 3.13 ls -lh dist .PHONY: format ## Auto-format rust and python source files format: uv run ruff check --fix $(sources) uv run ruff format $(sources) cargo fmt .PHONY: lint-python ## Lint python source files lint-python: uv run ruff check $(sources) uv run ruff format --check $(sources) uv run griffe dump -f -d google -LWARNING -o/dev/null python/pydantic_core $(mypy-stubtest) .PHONY: lint-rust ## Lint rust source files lint-rust: cargo fmt --version cargo fmt --all -- --check cargo clippy --version cargo clippy --tests -- -D warnings .PHONY: lint ## Lint rust and python source files lint: lint-python lint-rust .PHONY: pyright ## Perform type-checking with pyright pyright: uv run pyright .PHONY: test ## Run all tests test: uv run pytest .PHONY: testcov ## Run tests and generate a coverage report testcov: build-coverage @rm -rf htmlcov @mkdir -p htmlcov coverage run -m pytest coverage report coverage html -d htmlcov/python coverage-prepare html python/pydantic_core/*.so .PHONY: all ## Run the standard set of checks performed in CI all: format build-dev lint test .PHONY: clean ## Clear local caches and build artifacts clean: rm -rf `find . -name __pycache__` rm -f `find . -type f -name '*.py[co]' ` rm -f `find . -type f -name '*~' ` rm -f `find . -type f -name '.*~' ` rm -rf .cache rm -rf htmlcov rm -rf .pytest_cache rm -rf *.egg-info rm -f .coverage rm -f .coverage.* rm -rf build rm -rf perf.data* rm -rf python/pydantic_core/*.so .PHONY: help ## Display this message help: @grep -E \ '^.PHONY: .*?## .*$$' $(MAKEFILE_LIST) | \ sort | \ awk 'BEGIN {FS = ".PHONY: |## "}; {printf "\033[36m%-19s\033[0m %s\n", $$2, $$3}' pydantic-pydantic-ba0aa01/pydantic-core/README.md000066400000000000000000000111341517143232300216260ustar00rootroot00000000000000# pydantic-core [![CI](https://github.com/pydantic/pydantic-core/workflows/ci/badge.svg?event=push)](https://github.com/pydantic/pydantic-core/actions?query=event%3Apush+branch%3Amain+workflow%3Aci) [![Coverage](https://codecov.io/gh/pydantic/pydantic-core/branch/main/graph/badge.svg)](https://codecov.io/gh/pydantic/pydantic-core) [![pypi](https://img.shields.io/pypi/v/pydantic-core.svg)](https://pypi.python.org/pypi/pydantic-core) [![versions](https://img.shields.io/pypi/pyversions/pydantic-core.svg)](https://github.com/pydantic/pydantic-core) [![license](https://img.shields.io/github/license/pydantic/pydantic-core.svg)](https://github.com/pydantic/pydantic-core/blob/main/LICENSE) This package provides the core functionality for [pydantic](https://docs.pydantic.dev) validation and serialization. Pydantic-core is currently around 17x faster than pydantic V1. See [`tests/benchmarks/`](./tests/benchmarks/) for details. ## Example of direct usage *NOTE: You should not need to use pydantic-core directly; instead, use pydantic, which in turn uses pydantic-core.* ```py from pydantic_core import SchemaValidator, ValidationError v = SchemaValidator( { 'type': 'typed-dict', 'fields': { 'name': { 'type': 'typed-dict-field', 'schema': { 'type': 'str', }, }, 'age': { 'type': 'typed-dict-field', 'schema': { 'type': 'int', 'ge': 18, }, }, '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} # pydantic-core can also validate JSON directly r2 = v.validate_json('{"name": "Samuel", "age": 35}') assert r1 == r2 try: v.validate_python({'name': 'Samuel', 'age': 11}) except ValidationError as e: print(e) """ 1 validation error for model age Input should be greater than or equal to 18 [type=greater_than_equal, context={ge: 18}, input_value=11, input_type=int] """ ``` ## Getting Started ### Prerequisites You'll need: 1. **[Rust](https://rustup.rs/)** - Rust stable (or nightly for coverage) 2. **[uv](https://docs.astral.sh/uv/getting-started/installation/)** - Fast Python package manager (will install Python 3.9+ automatically) 3. **[git](https://git-scm.com/)** - For version control 4. **[make](https://www.gnu.org/software/make/)** - For running development commands (or use `nmake` on Windows) ### Quick Start ```bash # Clone the repository (or from your fork) git clone git@github.com:pydantic/pydantic-core.git cd pydantic-core # Install all dependencies using uv, setup pre-commit hooks, and build the development version make install ``` Verify your installation by running: ```bash make ``` This runs a full development cycle: formatting, building, linting, and testing ### Development Commands Run `make help` to see all available commands, or use these common ones: ```bash make build-dev # to build the package during development make build-prod # to perform an optimised build for benchmarking make test # to run the tests make testcov # to run the tests and generate a coverage report make lint # to run the linter make format # to format python and rust code make all # to run to run build-dev + format + lint + test ``` ### Useful Resources * [`python/pydantic_core/_pydantic_core.pyi`](./python/pydantic_core/_pydantic_core.pyi) - Python API types * [`python/pydantic_core/core_schema.py`](./python/pydantic_core/core_schema.py) - Core schema definitions * [`tests/`](./tests) - Comprehensive usage examples ## Profiling It's possible to profile the code using the [`flamegraph` utility from `flamegraph-rs`](https://github.com/flamegraph-rs/flamegraph). (Tested on Linux.) You can install this with `cargo install flamegraph`. Run `make build-profiling` to install a release build with debugging symbols included (needed for profiling). Once that is built, you can profile pytest benchmarks with (e.g.): ```bash flamegraph -- pytest tests/benchmarks/test_micro_benchmarks.py -k test_list_of_ints_core_py --benchmark-enable ``` The `flamegraph` command will produce an interactive SVG at `flamegraph.svg`. ## Releasing TBC (needs to be integrated into `pydantic` repository release process). pydantic-pydantic-ba0aa01/pydantic-core/benches/000077500000000000000000000000001517143232300217565ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/pydantic-core/benches/main.rs000066400000000000000000000741041517143232300232560ustar00rootroot00000000000000#![feature(test)] extern crate test; use std::ffi::{CStr, CString}; use test::{Bencher, black_box}; use pyo3::prelude::*; use pyo3::types::{PyDict, PyString}; use _pydantic_core::SchemaValidator; fn build_schema_validator_with_globals( py: Python, code: &CStr, globals: Option<&Bound<'_, PyDict>>, ) -> SchemaValidator { let schema = py.eval(code, globals, None).unwrap().extract().unwrap(); SchemaValidator::py_new(py, &schema, None, true).unwrap() } fn build_schema_validator(py: Python, code: &CStr) -> SchemaValidator { build_schema_validator_with_globals(py, code, None) } fn json<'a>(py: Python<'a>, code: &'a str) -> Bound<'a, PyAny> { black_box(PyString::new(py, code).into_any()) } #[bench] fn ints_json(bench: &mut Bencher) { Python::attach(|py| { let validator = build_schema_validator(py, c"{'type': 'int'}"); let result = validator .validate_json(py, &json(py, "123"), None, None, None, None, false.into(), None, None) .unwrap(); let result_int: i64 = result.extract(py).unwrap(); assert_eq!(result_int, 123); bench.iter(|| { black_box( validator .validate_json(py, &json(py, "123"), None, None, None, None, false.into(), None, None) .unwrap(), ) }) }) } #[bench] fn ints_python(bench: &mut Bencher) { Python::attach(|py| { let validator = build_schema_validator(py, c"{'type': 'int'}"); let Ok(input) = 123_i64.into_pyobject(py); let result = validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(); let result_int: i64 = result.extract(py).unwrap(); assert_eq!(result_int, 123); let input = black_box(input); bench.iter(|| { black_box( validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(), ) }) }) } #[bench] fn list_int_json(bench: &mut Bencher) { Python::attach(|py| { let validator = build_schema_validator(py, c"{'type': 'list', 'items_schema': {'type': 'int'}}"); let code = format!( "[{}]", (0..100).map(|x| x.to_string()).collect::>().join(",") ); bench.iter(|| { black_box( validator .validate_json(py, &json(py, &code), None, None, None, None, false.into(), None, None) .unwrap(), ) }) }) } fn list_int_input(py: Python<'_>) -> (SchemaValidator, Py) { let validator = build_schema_validator(py, c"{'type': 'list', 'items_schema': {'type': 'int'}}"); let code = CString::new(format!( "[{}]", (0..100).map(|x| x.to_string()).collect::>().join(",") )) .unwrap(); let input = py.eval(&code, None, None).unwrap(); (validator, input.unbind()) } #[bench] fn list_int_python(bench: &mut Bencher) { Python::attach(|py| { let (validator, input) = list_int_input(py); let input = black_box(input.bind(py)); bench.iter(|| { let v = validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(); black_box(v) }) }) } #[bench] fn list_int_python_isinstance(bench: &mut Bencher) { Python::attach(|py| { let (validator, input) = list_int_input(py); let input = black_box(input.bind(py)); let v = validator .isinstance_python(py, &input, None, None, None, None, None, None, None) .unwrap(); assert!(v); bench.iter(|| { let v = validator .isinstance_python(py, &input, None, None, None, None, None, None, None) .unwrap(); black_box(v) }) }) } #[bench] fn list_error_json(bench: &mut Bencher) { Python::attach(|py| { let validator = build_schema_validator(py, c"{'type': 'list', 'items_schema': {'type': 'int'}}"); let code = format!( "[{}]", (0..100) .map(|v| format!(r#""{}""#, as_str(v))) .collect::>() .join(", ") ); match validator.validate_json(py, &json(py, &code), None, None, None, None, false.into(), None, None) { Ok(_) => panic!("unexpectedly valid"), Err(e) => { let v = e.value(py); // println!("error: {}", v.to_string()); assert_eq!(v.getattr("title").unwrap().to_string(), "list[int]"); let error_count: i64 = v.call_method0("error_count").unwrap().extract().unwrap(); assert_eq!(error_count, 100); } }; bench.iter(|| { match validator.validate_json(py, &json(py, &code), None, None, None, None, false.into(), None, None) { Ok(_) => panic!("unexpectedly valid"), Err(e) => black_box(e), } }) }) } fn list_error_python_input(py: Python<'_>) -> (SchemaValidator, Py) { let validator = build_schema_validator(py, c"{'type': 'list', 'items_schema': {'type': 'int'}}"); let code = CString::new(format!( "[{}]", (0..100) .map(|v| format!(r#""{}""#, as_str(v))) .collect::>() .join(", ") )) .unwrap(); let input = py.eval(&code, None, None).unwrap().extract().unwrap(); match validator.validate_python(py, &input, None, None, None, None, None, false.into(), None, None) { Ok(_) => panic!("unexpectedly valid"), Err(e) => { let v = e.value(py); // println!("error: {}", v.to_string()); assert_eq!(v.getattr("title").unwrap().to_string(), "list[int]"); let error_count: i64 = v.call_method0("error_count").unwrap().extract().unwrap(); assert_eq!(error_count, 100); } }; (validator, input.unbind()) } #[bench] fn list_error_python(bench: &mut Bencher) { Python::attach(|py| { let (validator, input) = list_error_python_input(py); let input = black_box(input.bind(py)); bench.iter(|| { let result = validator.validate_python(py, &input, None, None, None, None, None, false.into(), None, None); match result { Ok(_) => panic!("unexpectedly valid"), Err(e) => black_box(e), } }) }) } #[bench] fn list_error_python_isinstance(bench: &mut Bencher) { Python::attach(|py| { let (validator, input) = list_error_python_input(py); let input = black_box(input.bind(py)); let r = validator .isinstance_python(py, &input, None, None, None, None, None, None, None) .unwrap(); assert!(!r); bench.iter(|| { black_box( validator .isinstance_python(py, &input, None, None, None, None, None, None, None) .unwrap(), ); }) }) } #[bench] fn list_any_json(bench: &mut Bencher) { Python::attach(|py| { let validator = build_schema_validator(py, c"{'type': 'list'}"); let code = format!( "[{}]", (0..100).map(|x| x.to_string()).collect::>().join(",") ); bench.iter(|| { black_box( validator .validate_json(py, &json(py, &code), None, None, None, None, false.into(), None, None) .unwrap(), ) }) }) } #[bench] fn list_any_python(bench: &mut Bencher) { Python::attach(|py| { let validator = build_schema_validator(py, c"{'type': 'list'}"); let code = CString::new(format!( "[{}]", (0..100).map(|x| x.to_string()).collect::>().join(",") )) .unwrap(); let input = py.eval(&code, None, None).unwrap(); let input = black_box(input); bench.iter(|| { let v = validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(); black_box(v) }) }) } fn as_char(i: u8) -> char { (i % 26 + 97) as char } fn as_str(i: u8) -> String { format!("{}{}", as_char(i / 26), as_char(i)) } #[bench] fn dict_json(bench: &mut Bencher) { Python::attach(|py| { let validator = build_schema_validator( py, c"{'type': 'dict', 'keys_schema': {'type': 'str'}, 'values_schema': {'type': 'int'}}", ); let code = format!( "{{{}}}", (0..100_u8) .map(|i| format!(r#""{}": {i}"#, as_str(i))) .collect::>() .join(", ") ); bench.iter(|| { black_box( validator .validate_json(py, &json(py, &code), None, None, None, None, false.into(), None, None) .unwrap(), ) }) }) } #[bench] fn dict_python(bench: &mut Bencher) { Python::attach(|py| { let validator = build_schema_validator( py, c"{'type': 'dict', 'keys_schema': {'type': 'str'}, 'values_schema': {'type': 'int'}}", ); let code = CString::new(format!( "{{{}}}", (0..100_u8) .map(|i| format!(r#""{}{}": {i}"#, as_char(i / 26), as_char(i))) .collect::>() .join(", ") )) .unwrap(); let input = py.eval(&code, None, None).unwrap(); let input = black_box(input); bench.iter(|| { let v = validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(); black_box(v) }) }) } #[bench] fn dict_value_error(bench: &mut Bencher) { Python::attach(|py| { let validator = build_schema_validator( py, cr"{ 'type': 'dict', 'keys_schema': {'type': 'str'}, 'values_schema': {'type': 'int', 'lt': 0}, }", ); let code = CString::new(format!( "{{{}}}", (0..100_u8) .map(|i| format!(r#""{}": {i}"#, as_str(i))) .collect::>() .join(", ") )) .unwrap(); let input = py.eval(&code, None, None).unwrap(); match validator.validate_python(py, &input, None, None, None, None, None, false.into(), None, None) { Ok(_) => panic!("unexpectedly valid"), Err(e) => { let v = e.value(py); // println!("error: {}", v.to_string()); assert_eq!(v.getattr("title").unwrap().to_string(), "dict[str,constrained-int]"); let error_count: i64 = v.call_method0("error_count").unwrap().extract().unwrap(); assert_eq!(error_count, 100); } }; let input = black_box(input); bench.iter(|| { let result = validator.validate_python(py, &input, None, None, None, None, None, false.into(), None, None); match result { Ok(_) => panic!("unexpectedly valid"), Err(e) => black_box(e), } }) }) } #[bench] fn typed_dict_json(bench: &mut Bencher) { Python::attach(|py| { let validator = build_schema_validator( py, cr"{ 'type': 'typed-dict', 'extra_behavior': 'ignore', 'fields': { 'a': {'type': 'typed-dict-field', 'schema': {'type': 'int'}}, 'b': {'type': 'typed-dict-field', 'schema': {'type': 'int'}}, 'c': {'type': 'typed-dict-field', 'schema': {'type': 'int'}}, 'd': {'type': 'typed-dict-field', 'schema': {'type': 'int'}}, 'e': {'type': 'typed-dict-field', 'schema': {'type': 'int'}}, 'f': {'type': 'typed-dict-field', 'schema': {'type': 'int'}}, 'g': {'type': 'typed-dict-field', 'schema': {'type': 'int'}}, 'h': {'type': 'typed-dict-field', 'schema': {'type': 'int'}}, 'i': {'type': 'typed-dict-field', 'schema': {'type': 'int'}}, 'j': {'type': 'typed-dict-field', 'schema': {'type': 'int'}}, }, }", ); let code = r#"{"a": 1, "b": 2, "c": 3, "d": 4, "e": 5, "f": 6, "g": 7, "h": 8, "i": 9, "j": 0}"#; bench.iter(|| { black_box( validator .validate_json(py, &json(py, code), None, None, None, None, false.into(), None, None) .unwrap(), ) }) }) } #[bench] fn typed_dict_python(bench: &mut Bencher) { Python::attach(|py| { let validator = build_schema_validator( py, cr"{ 'type': 'typed-dict', 'extra_behavior': 'ignore', 'fields': { 'a': {'type': 'typed-dict-field', 'schema': {'type': 'int'}}, 'b': {'type': 'typed-dict-field', 'schema': {'type': 'int'}}, 'c': {'type': 'typed-dict-field', 'schema': {'type': 'int'}}, 'd': {'type': 'typed-dict-field', 'schema': {'type': 'int'}}, 'e': {'type': 'typed-dict-field', 'schema': {'type': 'int'}}, 'f': {'type': 'typed-dict-field', 'schema': {'type': 'int'}}, 'g': {'type': 'typed-dict-field', 'schema': {'type': 'int'}}, 'h': {'type': 'typed-dict-field', 'schema': {'type': 'int'}}, 'i': {'type': 'typed-dict-field', 'schema': {'type': 'int'}}, 'j': {'type': 'typed-dict-field', 'schema': {'type': 'int'}}, }, }", ); let code = cr#"{"a": 1, "b": 2, "c": 3, "d": 4, "e": 5, "f": 6, "g": 7, "h": 8, "i": 9, "j": 0}"#; let input = py.eval(&code, None, None).unwrap(); let input = black_box(input); bench.iter(|| { let v = validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(); black_box(v) }) }) } #[bench] fn typed_dict_deep_error(bench: &mut Bencher) { Python::attach(|py| { let validator = build_schema_validator( py, cr"{ 'type': 'typed-dict', 'fields': { 'field_a': {'type': 'typed-dict-field', 'schema': {'type': 'str'}}, 'field_b': { 'type': 'typed-dict-field', 'schema': { 'type': 'typed-dict', 'fields': { 'field_c': {'type': 'typed-dict-field','schema': {'type': 'str'}}, 'field_d': { 'type': 'typed-dict-field', 'schema': { 'type': 'typed-dict', 'fields': {'field_e': {'type': 'typed-dict-field','schema': {'type': 'str'}}, 'field_f': {'type': 'typed-dict-field','schema': {'type': 'int'}}}, } }, }, } }, }, }", ); let code = c"{'field_a': '1', 'field_b': {'field_c': '2', 'field_d': {'field_e': '4', 'field_f': 'xx'}}}"; let input = py.eval(code, None, None).unwrap(); let input = black_box(input); match validator.validate_python(py, &input, None, None, None, None, None, false.into(), None, None) { Ok(_) => panic!("unexpectedly valid"), Err(e) => { let v = e.value(py); // println!("error: {}", v.to_string()); assert_eq!(v.getattr("title").unwrap().to_string(), "typed-dict"); let error_count: i64 = v.call_method0("error_count").unwrap().extract().unwrap(); assert_eq!(error_count, 1); } }; bench.iter(|| { let result = validator.validate_python(py, &input, None, None, None, None, None, false.into(), None, None); match result { Ok(_) => panic!("unexpectedly valid"), Err(e) => black_box(e), } }) }) } #[bench] fn complete_model(bench: &mut Bencher) { Python::attach(|py| { let sys_path = py.import("sys").unwrap().getattr("path").unwrap(); sys_path.call_method1("append", ("./tests/benchmarks/",)).unwrap(); let complete_schema = py.import("complete_schema").unwrap(); let schema = complete_schema.call_method0("schema").unwrap(); let validator = SchemaValidator::py_new(py, &schema, None, true).unwrap(); let input = complete_schema.call_method0("input_data_lax").unwrap(); let input = black_box(input); bench.iter(|| { black_box( validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(), ); }) }) } #[bench] fn nested_model_using_definitions(bench: &mut Bencher) { Python::attach(|py| { let sys_path = py.import("sys").unwrap().getattr("path").unwrap(); sys_path.call_method1("append", ("./tests/benchmarks/",)).unwrap(); let complete_schema = py.import("nested_schema").unwrap(); let schema = complete_schema.call_method0("schema_using_defs").unwrap(); let validator = SchemaValidator::py_new(py, &schema, None, true).unwrap(); let input = complete_schema.call_method0("input_data_valid").unwrap(); let input = black_box(input); validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(); bench.iter(|| { black_box( validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(), ); }) }) } #[bench] fn nested_model_inlined(bench: &mut Bencher) { Python::attach(|py| { let sys_path = py.import("sys").unwrap().getattr("path").unwrap(); sys_path.call_method1("append", ("./tests/benchmarks/",)).unwrap(); let complete_schema = py.import("nested_schema").unwrap(); let schema = complete_schema.call_method0("inlined_schema").unwrap(); let validator = SchemaValidator::py_new(py, &schema, None, true).unwrap(); let input = complete_schema.call_method0("input_data_valid").unwrap(); let input = black_box(input); validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(); bench.iter(|| { black_box( validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(), ); }) }) } #[bench] fn literal_ints_few_python(bench: &mut Bencher) { Python::attach(|py| { let validator = build_schema_validator(py, c"{'type': 'literal', 'expected': list(range(5))}"); let Ok(input) = 4_i64.into_pyobject(py); let result = validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(); let result_int: i64 = result.extract(py).unwrap(); assert_eq!(result_int, 4); let input = black_box(input); bench.iter(|| { black_box( validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(), ) }) }) } #[bench] fn literal_strings_few_small_python(bench: &mut Bencher) { Python::attach(|py| { let validator = build_schema_validator(py, c"{'type': 'literal', 'expected': [f'{idx}' for idx in range(5)]}"); let input = py.eval(c"'4'", None, None).unwrap(); let input_str: String = input.extract().unwrap(); let result = validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(); let result_str: String = result.extract(py).unwrap(); assert_eq!(result_str, input_str); let input = black_box(input); bench.iter(|| { black_box( validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(), ) }) }) } #[bench] fn literal_strings_few_large_python(bench: &mut Bencher) { Python::attach(|py| { let validator = build_schema_validator( py, c"{'type': 'literal', 'expected': ['a' * 25 + f'{idx}' for idx in range(5)]}", ); let input = py.eval(c"'a' * 25 + '4'", None, None).unwrap(); let input_str: String = input.extract().unwrap(); let result = validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(); let result_str: String = result.extract(py).unwrap(); assert_eq!(result_str, input_str); let input = black_box(input); bench.iter(|| { black_box( validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(), ) }) }) } #[bench] fn literal_enums_few_python(bench: &mut Bencher) { Python::attach(|py| { let globals = PyDict::new(py); py.run( cr" from enum import Enum class Foo(Enum): v1 = object() v2 = object() v3 = object() v4 = object() ", Some(&globals), None, ) .unwrap(); let validator = build_schema_validator_with_globals( py, c"{'type': 'literal', 'expected': [Foo.v1, Foo.v2, Foo.v3, Foo.v4]}", Some(&globals), ); let input = py.eval(c"Foo.v4", Some(&globals), None).unwrap(); let result = validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(); assert!(input.eq(result).unwrap()); let input = black_box(input); bench.iter(|| { black_box( validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(), ) }) }) } #[bench] fn literal_ints_many_python(bench: &mut Bencher) { Python::attach(|py| { let validator = build_schema_validator(py, c"{'type': 'literal', 'expected': list(range(100))}"); let Ok(input) = 99_i64.into_pyobject(py); let result = validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(); let result_int: i64 = result.extract(py).unwrap(); assert_eq!(result_int, 99); let input = black_box(input); bench.iter(|| { black_box( validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(), ) }) }) } #[bench] fn literal_strings_many_small_python(bench: &mut Bencher) { Python::attach(|py| { let validator = build_schema_validator(py, c"{'type': 'literal', 'expected': [f'{idx}' for idx in range(100)]}"); let input = py.eval(c"'99'", None, None).unwrap(); let input_str: String = input.extract().unwrap(); let result = validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(); let result_str: String = result.extract(py).unwrap(); assert_eq!(result_str, input_str); let input = black_box(input); bench.iter(|| { black_box( validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(), ) }) }) } #[bench] fn literal_strings_many_large_python(bench: &mut Bencher) { Python::attach(|py| { let validator = build_schema_validator( py, c"{'type': 'literal', 'expected': ['a' * 25 + f'{idx}' for idx in range(100)]}", ); let input = py.eval(c"'a' * 25 + '99'", None, None).unwrap(); let input_str: String = input.extract().unwrap(); let result = validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(); let result_str: String = result.extract(py).unwrap(); assert_eq!(result_str, input_str); let input = black_box(input); bench.iter(|| { black_box( validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(), ) }) }) } #[bench] fn literal_ints_many_json(bench: &mut Bencher) { Python::attach(|py| { let validator = build_schema_validator(py, c"{'type': 'literal', 'expected': list(range(100))}"); let input_json = py.eval(c"'99'", None, None).unwrap(); let result = validator .validate_json(py, &input_json, None, None, None, None, false.into(), None, None) .unwrap(); let result_int: i64 = result.extract(py).unwrap(); assert_eq!(result_int, 99); let input_json = black_box(input_json); bench.iter(|| { black_box( validator .validate_json(py, &input_json, None, None, None, None, false.into(), None, None) .unwrap(), ) }) }) } #[bench] fn literal_strings_many_large_json(bench: &mut Bencher) { Python::attach(|py| { let validator = build_schema_validator( py, c"{'type': 'literal', 'expected': ['a' * 25 + f'{idx}' for idx in range(100)]}", ); let input = py.eval(c"'a' * 25 + '99'", None, None).unwrap(); let input_json = py.eval(c"'\"' + 'a' * 25 + '99' + '\"'", None, None).unwrap(); let input_str: String = input.extract().unwrap(); let result = validator .validate_json(py, &input_json, None, None, None, None, false.into(), None, None) .unwrap(); let result_str: String = result.extract(py).unwrap(); assert_eq!(result_str, input_str); let input_json = black_box(input_json); bench.iter(|| { black_box( validator .validate_json(py, &input_json, None, None, None, None, false.into(), None, None) .unwrap(), ) }) }) } #[bench] fn literal_mixed_few_python(bench: &mut Bencher) { Python::attach(|py| { let globals = PyDict::new(py); py.run( cr" from enum import Enum class Foo(Enum): v1 = object() v2 = object() v3 = object() v4 = object() ", Some(&globals), None, ) .unwrap(); let validator = build_schema_validator_with_globals( py, c"{'type': 'literal', 'expected': [None, 'null', -1, Foo.v4]}", Some(&globals), ); // String { let input = py.eval(c"'null'", None, None).unwrap(); let input_str: String = input.extract().unwrap(); let result = validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(); let result_str: String = result.extract(py).unwrap(); assert_eq!(result_str, input_str); let input = black_box(input); bench.iter(|| { black_box( validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(), ) }) } // Int { let input = py.eval(c"-1", None, None).unwrap(); let input_int: i64 = input.extract().unwrap(); let result = validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(); let result_int: i64 = result.extract(py).unwrap(); assert_eq!(result_int, input_int); let input = black_box(input); bench.iter(|| { black_box( validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(), ) }) } // None { let input = py.eval(c"None", None, None).unwrap(); let result = validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(); assert!(input.eq(result).unwrap()); let input = black_box(input); bench.iter(|| { black_box( validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(), ) }) } // Enum { let input = py.eval(c"Foo.v4", Some(&globals), None).unwrap(); let result = validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(); assert!(input.eq(result).unwrap()); let input = black_box(input); bench.iter(|| { black_box( validator .validate_python(py, &input, None, None, None, None, None, false.into(), None, None) .unwrap(), ) }) } }) } pydantic-pydantic-ba0aa01/pydantic-core/build.rs000066400000000000000000000011071517143232300220130ustar00rootroot00000000000000fn main() { pyo3_build_config::use_pyo3_cfgs(); if let Some(true) = version_check::supports_feature("coverage_attribute") { println!("cargo:rustc-cfg=has_coverage_attribute"); } println!("cargo:rustc-check-cfg=cfg(has_coverage_attribute)"); if std::env::var("RUSTFLAGS") .unwrap_or_default() .contains("-Cprofile-use=") { println!("cargo:rustc-cfg=specified_profile_use"); } println!("cargo:rustc-check-cfg=cfg(specified_profile_use)"); println!("cargo:rustc-env=PROFILE={}", std::env::var("PROFILE").unwrap()); } pydantic-pydantic-ba0aa01/pydantic-core/package.json000066400000000000000000000013331517143232300226350ustar00rootroot00000000000000{ "name": "pydantic-core", "version": "1.0.0", "description": "for running wasm tests.", "author": "Samuel Colvin", "license": "MIT", "homepage": "https://github.com/pydantic/pydantic", "main": "tests/emscripten_runner.js", "dependencies": { "prettier": "^2.7.1", "pyodide": "^0.28.3" }, "scripts": { "test": "node tests/emscripten_runner.js", "format": "prettier --write 'tests/emscripten_runner.js' 'wasm-preview/*.{html,js}'", "lint": "prettier --check 'tests/emscripten_runner.js' 'wasm-preview/*.{html,js}'" }, "prettier": { "singleQuote": true, "trailingComma": "all", "tabWidth": 2, "printWidth": 119, "bracketSpacing": false, "arrowParens": "avoid" } } pydantic-pydantic-ba0aa01/pydantic-core/pyproject.toml000066400000000000000000000130131517143232300232610ustar00rootroot00000000000000[build-system] requires = ['maturin>=1.10,<2'] build-backend = 'maturin' [project] name = 'pydantic_core' description = "Core functionality for Pydantic validation and serialization" requires-python = '>=3.9' license = 'MIT' license-files = ['LICENSE'] authors = [ { name = 'Samuel Colvin', email = 's@muelcolvin.com' }, { name = 'Adrian Garcia Badaracco', email = '1755071+adriangb@users.noreply.github.com' }, { name = 'David Montague', email = 'david@pydantic.dev' }, { name = 'David Hewitt', email = 'mail@davidhewitt.dev' }, { name = 'Sydney Runkle', email = 'sydneymarierunkle@gmail.com' }, { name = 'Victorien Plot', email = 'contact@vctrn.dev' }, ] classifiers = [ 'Development Status :: 3 - Alpha', 'Programming Language :: Python', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3 :: Only', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: 3.13', 'Programming Language :: Python :: 3.14', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Programming Language :: Python :: Implementation :: GraalPy', 'Programming Language :: Rust', 'Framework :: Pydantic', 'Intended Audience :: Developers', 'Intended Audience :: Information Technology', 'Operating System :: POSIX :: Linux', 'Operating System :: Microsoft :: Windows', 'Operating System :: MacOS', 'Typing :: Typed', ] dependencies = ['typing-extensions>=4.14.1'] dynamic = ['readme', 'version'] [project.urls] Homepage = 'https://github.com/pydantic' Funding = 'https://github.com/sponsors/samuelcolvin' Source = 'https://github.com/pydantic/pydantic/tree/main/pydantic-core' [dependency-groups] dev = ["maturin"] testing-extra = [ { include-group = "dev" }, 'coverage', 'dirty-equals', 'exceptiongroup; python_version < "3.11"', 'hypothesis', 'inline-snapshot', # numpy doesn't offer prebuilt wheels for all versions and platforms we test in CI e.g. aarch64 musllinux 'numpy; python_version < "3.13" and implementation_name == "cpython" and platform_machine == "x86_64"', # pandas doesn't offer prebuilt wheels for all versions and platforms we test in CI e.g. aarch64 musllinux 'pandas; python_version < "3.13" and implementation_name == "cpython" and platform_machine == "x86_64"', 'pytest', # pytest-examples currently depends on aiohttp via black; we don't want to build it on platforms like aarch64 musllinux in CI 'pytest-examples; implementation_name == "cpython" and platform_machine == "x86_64"', 'pytest-mock', 'pytest-pretty', 'pytest-run-parallel', 'pytest-benchmark', 'pytest-timeout', 'python-dateutil', 'typing-inspection>=0.4.1', 'tzdata', ] linting = [ { include-group = "dev" }, 'griffe', 'mypy', 'pre-commit', 'pyright', 'ruff', ] wasm = [{ include-group = "dev" }, 'ruff'] codspeed = [ # codspeed is only run on CI, with latest version of CPython 'pytest-codspeed; python_version == "3.13" and implementation_name == "cpython"', ] [tool.maturin] python-source = "python" module-name = "pydantic_core._pydantic_core" bindings = 'pyo3' # when using `uv` to build `pydantic-core`, use the `dev` profile # can override by e.g. `make build-pgo` and then using `uv run --no-sync` editable-profile = 'dev' [tool.ruff] line-length = 120 target-version = 'py39' [tool.ruff.lint] extend-select = ['Q', 'RUF100', 'C90', 'I', 'UP'] extend-ignore = [ 'E721', # using type() instead of isinstance() - we use this in tests ] flake8-quotes = { inline-quotes = 'single', multiline-quotes = 'double' } mccabe = { max-complexity = 13 } isort = { known-first-party = ['pydantic_core', 'tests'] } [tool.ruff.lint.pyupgrade] keep-runtime-typing = true [tool.ruff.format] quote-style = 'single' [tool.pytest.ini_options] testpaths = 'tests' log_format = '%(name)s %(levelname)s: %(message)s' filterwarnings = [ 'error', # Python 3.9 and below allowed truncation of float to integers in some # cases, by not making this an error we can test for this behaviour 'ignore:(.+)Implicit conversion to integers using __int__ is deprecated', ] timeout = 30 xfail_strict = true # min, max, mean, stddev, median, iqr, outliers, ops, rounds, iterations addopts = [ '--benchmark-columns', 'min,mean,stddev,outliers,rounds,iterations', '--benchmark-group-by', 'group', '--benchmark-warmup', 'on', '--benchmark-disable', # this is enable by `make benchmark` when you actually want to run benchmarks ] [tool.coverage.run] source = ['pydantic_core'] branch = true [tool.coverage.report] precision = 2 exclude_also = [ 'raise\sNotImplementedError', '@(typing\.)?overload', 'class .*\bProtocol\):', '(typing\.)?.assert_never', ] # configuring https://github.com/pydantic/hooky [tool.hooky] reviewers = ['Viicos', 'davidhewitt'] require_change_file = false [tool.pyright] include = ['python/pydantic_core', 'tests/test_typing.py'] reportUnnecessaryTypeIgnoreComment = true [tool.inline-snapshot.shortcuts] fix = ["create", "fix"] [tool.uv] required-version = '>=0.7.2' cache-keys = [ { file = "pyproject.toml" }, { file = "setup.py" }, { file = "setup.cfg" }, { file = "Cargo.toml" }, { file = "Cargo.lock" }, { file = "**/*.rs" }, { env = "MATURIN_PEP517_ARGS" }, { env = "RUSTFLAGS" } ] pydantic-pydantic-ba0aa01/pydantic-core/python/000077500000000000000000000000001517143232300216705ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/pydantic-core/python/pydantic_core/000077500000000000000000000000001517143232300245135ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/pydantic-core/python/pydantic_core/__init__.py000066400000000000000000000117731517143232300266350ustar00rootroot00000000000000from __future__ import annotations import sys as _sys from typing import Any as _Any from typing_extensions import Sentinel from ._pydantic_core import ( ArgsKwargs, MultiHostUrl, PydanticCustomError, PydanticKnownError, PydanticOmit, PydanticSerializationError, PydanticSerializationUnexpectedValue, PydanticUndefined, PydanticUndefinedType, PydanticUseDefault, SchemaError, SchemaSerializer, SchemaValidator, Some, TzInfo, Url, ValidationError, __version__, from_json, to_json, to_jsonable_python, ) from .core_schema import CoreConfig, CoreSchema, CoreSchemaType, ErrorType if _sys.version_info < (3, 11): from typing_extensions import NotRequired as _NotRequired else: from typing import NotRequired as _NotRequired if _sys.version_info < (3, 12): from typing_extensions import TypedDict as _TypedDict else: from typing import TypedDict as _TypedDict __all__ = [ '__version__', 'UNSET', 'CoreConfig', 'CoreSchema', 'CoreSchemaType', 'SchemaValidator', 'SchemaSerializer', 'Some', 'Url', 'MultiHostUrl', 'ArgsKwargs', 'PydanticUndefined', 'PydanticUndefinedType', 'SchemaError', 'ErrorDetails', 'InitErrorDetails', 'ValidationError', 'PydanticCustomError', 'PydanticKnownError', 'PydanticOmit', 'PydanticUseDefault', 'PydanticSerializationError', 'PydanticSerializationUnexpectedValue', 'TzInfo', 'to_json', 'from_json', 'to_jsonable_python', ] class ErrorDetails(_TypedDict): type: str """ The type of error that occurred, this is an identifier designed for programmatic use that will change rarely or never. `type` is unique for each error message, and can hence be used as an identifier to build custom error messages. """ loc: tuple[int | str, ...] """Tuple of strings and ints identifying where in the schema the error occurred.""" msg: str """A human readable error message.""" input: _Any """The input data at this `loc` that caused the error.""" ctx: _NotRequired[dict[str, _Any]] """ Values which are required to render the error message, and could hence be useful in rendering custom error messages. Also useful for passing custom error data forward. """ url: _NotRequired[str] """ The documentation URL giving information about the error. No URL is available if a [`PydanticCustomError`][pydantic_core.PydanticCustomError] is used. """ class InitErrorDetails(_TypedDict): type: str | PydanticCustomError """The type of error that occurred, this should be a "slug" identifier that changes rarely or never.""" loc: _NotRequired[tuple[int | str, ...]] """Tuple of strings and ints identifying where in the schema the error occurred.""" input: _Any """The input data at this `loc` that caused the error.""" ctx: _NotRequired[dict[str, _Any]] """ Values which are required to render the error message, and could hence be useful in rendering custom error messages. Also useful for passing custom error data forward. """ class ErrorTypeInfo(_TypedDict): """ Gives information about errors. """ type: ErrorType """The type of error that occurred, this should be a "slug" identifier that changes rarely or never.""" message_template_python: str """String template to render a human readable error message from using context, when the input is Python.""" example_message_python: str """Example of a human readable error message, when the input is Python.""" message_template_json: _NotRequired[str] """String template to render a human readable error message from using context, when the input is JSON data.""" example_message_json: _NotRequired[str] """Example of a human readable error message, when the input is JSON data.""" example_context: dict[str, _Any] | None """Example of context values.""" class MultiHostHost(_TypedDict): """ A host part of a multi-host URL. """ username: str | None """The username part of this host, or `None`.""" password: str | None """The password part of this host, or `None`.""" host: str | None """The host part of this host, or `None`.""" port: int | None """The port part of this host, or `None`.""" MISSING = Sentinel('MISSING') """A singleton indicating a field value was not provided during validation. This singleton can be used a default value, as an alternative to `None` when it has an explicit meaning. During serialization, any field with `MISSING` as a value is excluded from the output. Example: ```python from pydantic import BaseModel from pydantic_core import MISSING class Configuration(BaseModel): timeout: int | None | MISSING = MISSING # configuration defaults, stored somewhere else: defaults = {'timeout': 200} conf = Configuration.model_validate({...}) timeout = conf.timeout if timeout.timeout is not MISSING else defaults['timeout'] """ pydantic-pydantic-ba0aa01/pydantic-core/python/pydantic_core/_pydantic_core.pyi000066400000000000000000001315541517143232300302310ustar00rootroot00000000000000import datetime from collections.abc import Mapping from typing import Any, Callable, Generic, Literal, TypeVar, final from _typeshed import SupportsAllComparisons from typing_extensions import LiteralString, Self, TypeAlias from pydantic_core import ErrorDetails, ErrorTypeInfo, InitErrorDetails, MultiHostHost from pydantic_core.core_schema import CoreConfig, CoreSchema, ErrorType, ExtraBehavior __all__ = [ '__version__', 'build_profile', 'build_info', '_recursion_limit', 'ArgsKwargs', 'SchemaValidator', 'SchemaSerializer', 'Url', 'MultiHostUrl', 'SchemaError', 'ValidationError', 'PydanticCustomError', 'PydanticKnownError', 'PydanticOmit', 'PydanticUseDefault', 'PydanticSerializationError', 'PydanticSerializationUnexpectedValue', 'PydanticUndefined', 'PydanticUndefinedType', 'Some', 'to_json', 'from_json', 'to_jsonable_python', 'list_all_errors', 'TzInfo', ] __version__: str build_profile: str build_info: str _recursion_limit: int _T = TypeVar('_T', default=Any, covariant=True) _StringInput: TypeAlias = 'dict[str, _StringInput]' @final class Some(Generic[_T]): """ Similar to Rust's [`Option::Some`](https://doc.rust-lang.org/std/option/enum.Option.html) type, this identifies a value as being present, and provides a way to access it. Generally used in a union with `None` to different between "some value which could be None" and no value. """ __match_args__ = ('value',) @property def value(self) -> _T: """ Returns the value wrapped by `Some`. """ @classmethod def __class_getitem__(cls, item: Any, /) -> type[Self]: ... @final class SchemaValidator: """ `SchemaValidator` is the Python wrapper for `pydantic-core`'s Rust validation logic, internally it owns one `CombinedValidator` which may in turn own more `CombinedValidator`s which make up the full schema validator. """ # note: pyo3 currently supports __new__, but not __init__, though we include __init__ stubs # and docstrings here (and in the following classes) for documentation purposes def __init__(self, schema: CoreSchema, config: CoreConfig | None = None, _use_prebuilt: bool = True) -> None: """Initializes the `SchemaValidator`. Arguments: schema: The `CoreSchema` to use for validation. config: Optionally a [`CoreConfig`][pydantic_core.core_schema.CoreConfig] to configure validation. _use_prebuilt: Whether to use pre-built validators (False during rebuilds to avoid stale references). """ def __new__(cls, schema: CoreSchema, config: CoreConfig | None = None, _use_prebuilt: bool = True) -> Self: ... @property def title(self) -> str: """ The title of the schema, as used in the heading of [`ValidationError.__str__()`][pydantic_core.ValidationError]. """ def validate_python( self, input: Any, *, strict: bool | None = None, extra: ExtraBehavior | None = None, from_attributes: bool | None = None, context: Any | None = None, self_instance: Any | None = None, allow_partial: bool | Literal['off', 'on', 'trailing-strings'] = False, by_alias: bool | None = None, by_name: bool | None = None, ) -> Any: """ Validate a Python object against the schema and return the validated object. Arguments: input: The Python object to validate. strict: Whether to validate the object in strict mode. If `None`, the value of [`CoreConfig.strict`][pydantic_core.core_schema.CoreConfig] is used. extra: Whether to ignore, allow, or forbid extra data during model validation. If `None`, the value of [`CoreConfig.extra_fields_behavior`][pydantic_core.core_schema.CoreConfig] is used. from_attributes: Whether to validate objects as inputs to models by extracting attributes. If `None`, the value of [`CoreConfig.from_attributes`][pydantic_core.core_schema.CoreConfig] is used. context: The context to use for validation, this is passed to functional validators as [`info.context`][pydantic_core.core_schema.ValidationInfo.context]. self_instance: An instance of a model set attributes on from validation, this is used when running validation from the `__init__` method of a model. allow_partial: Whether to allow partial validation; if `True` errors in the last element of sequences and mappings are ignored. `'trailing-strings'` means any final unfinished JSON string is included in the result. by_alias: Whether to use the field's alias when validating against the provided input data. by_name: Whether to use the field's name when validating against the provided input data. Raises: ValidationError: If validation fails. Exception: Other error types maybe raised if internal errors occur. Returns: The validated object. """ def isinstance_python( self, input: Any, *, strict: bool | None = None, extra: ExtraBehavior | None = None, from_attributes: bool | None = None, context: Any | None = None, self_instance: Any | None = None, by_alias: bool | None = None, by_name: bool | None = None, ) -> bool: """ Similar to [`validate_python()`][pydantic_core.SchemaValidator.validate_python] but returns a boolean. Arguments match `validate_python()`. This method will not raise `ValidationError`s but will raise internal errors. Returns: `True` if validation succeeds, `False` if validation fails. """ def validate_json( self, input: str | bytes | bytearray, *, strict: bool | None = None, extra: ExtraBehavior | None = None, context: Any | None = None, self_instance: Any | None = None, allow_partial: bool | Literal['off', 'on', 'trailing-strings'] = False, by_alias: bool | None = None, by_name: bool | None = None, ) -> Any: """ Validate JSON data directly against the schema and return the validated Python object. This method should be significantly faster than `validate_python(json.loads(json_data))` as it avoids the need to create intermediate Python objects It also handles constructing the correct Python type even in strict mode, where `validate_python(json.loads(json_data))` would fail validation. Arguments: input: The JSON data to validate. strict: Whether to validate the object in strict mode. If `None`, the value of [`CoreConfig.strict`][pydantic_core.core_schema.CoreConfig] is used. extra: Whether to ignore, allow, or forbid extra data during model validation. If `None`, the value of [`CoreConfig.extra_fields_behavior`][pydantic_core.core_schema.CoreConfig] is used. context: The context to use for validation, this is passed to functional validators as [`info.context`][pydantic_core.core_schema.ValidationInfo.context]. self_instance: An instance of a model set attributes on from validation. allow_partial: Whether to allow partial validation; if `True` incomplete JSON will be parsed successfully and errors in the last element of sequences and mappings are ignored. `'trailing-strings'` means any final unfinished JSON string is included in the result. by_alias: Whether to use the field's alias when validating against the provided input data. by_name: Whether to use the field's name when validating against the provided input data. Raises: ValidationError: If validation fails or if the JSON data is invalid. Exception: Other error types maybe raised if internal errors occur. Returns: The validated Python object. """ def validate_strings( self, input: _StringInput, *, strict: bool | None = None, extra: ExtraBehavior | None = None, context: Any | None = None, allow_partial: bool | Literal['off', 'on', 'trailing-strings'] = False, by_alias: bool | None = None, by_name: bool | None = None, ) -> Any: """ Validate a string against the schema and return the validated Python object. This is similar to `validate_json` but applies to scenarios where the input will be a string but not JSON data, e.g. URL fragments, query parameters, etc. Arguments: input: The input as a string, or bytes/bytearray if `strict=False`. strict: Whether to validate the object in strict mode. If `None`, the value of [`CoreConfig.strict`][pydantic_core.core_schema.CoreConfig] is used. extra: Whether to ignore, allow, or forbid extra data during model validation. If `None`, the value of [`CoreConfig.extra_fields_behavior`][pydantic_core.core_schema.CoreConfig] is used. context: The context to use for validation, this is passed to functional validators as [`info.context`][pydantic_core.core_schema.ValidationInfo.context]. allow_partial: Whether to allow partial validation; if `True` errors in the last element of sequences and mappings are ignored. `'trailing-strings'` means any final unfinished JSON string is included in the result. by_alias: Whether to use the field's alias when validating against the provided input data. by_name: Whether to use the field's name when validating against the provided input data. Raises: ValidationError: If validation fails or if the JSON data is invalid. Exception: Other error types maybe raised if internal errors occur. Returns: The validated Python object. """ def validate_assignment( self, obj: Any, field_name: str, field_value: Any, *, strict: bool | None = None, extra: ExtraBehavior | None = None, from_attributes: bool | None = None, context: Any | None = None, by_alias: bool | None = None, by_name: bool | None = None, ) -> dict[str, Any] | tuple[dict[str, Any], dict[str, Any] | None, set[str]]: """ Validate an assignment to a field on a model. Arguments: obj: The model instance being assigned to. field_name: The name of the field to validate assignment for. field_value: The value to assign to the field. strict: Whether to validate the object in strict mode. If `None`, the value of [`CoreConfig.strict`][pydantic_core.core_schema.CoreConfig] is used. extra: Whether to ignore, allow, or forbid extra data during model validation. If `None`, the value of [`CoreConfig.extra_fields_behavior`][pydantic_core.core_schema.CoreConfig] is used. from_attributes: Whether to validate objects as inputs to models by extracting attributes. If `None`, the value of [`CoreConfig.from_attributes`][pydantic_core.core_schema.CoreConfig] is used. context: The context to use for validation, this is passed to functional validators as [`info.context`][pydantic_core.core_schema.ValidationInfo.context]. by_alias: Whether to use the field's alias when validating against the provided input data. by_name: Whether to use the field's name when validating against the provided input data. Raises: ValidationError: If validation fails. Exception: Other error types maybe raised if internal errors occur. Returns: Either the model dict or a tuple of `(model_data, model_extra, fields_set)` """ def get_default_value(self, *, strict: bool | None = None, context: Any = None) -> Some | None: """ Get the default value for the schema, including running default value validation. Arguments: strict: Whether to validate the default value in strict mode. If `None`, the value of [`CoreConfig.strict`][pydantic_core.core_schema.CoreConfig] is used. context: The context to use for validation, this is passed to functional validators as [`info.context`][pydantic_core.core_schema.ValidationInfo.context]. Raises: ValidationError: If validation fails. Exception: Other error types maybe raised if internal errors occur. Returns: `None` if the schema has no default value, otherwise a [`Some`][pydantic_core.Some] containing the default. """ # In reality, `bool` should be replaced by `Literal[True]` but mypy fails to correctly apply bidirectional type inference # (e.g. when using `{'a': {'b': True}}`). _IncEx: TypeAlias = set[int] | set[str] | Mapping[int, _IncEx | bool] | Mapping[str, _IncEx | bool] @final class SchemaSerializer: """ `SchemaSerializer` is the Python wrapper for `pydantic-core`'s Rust serialization logic, internally it owns one `CombinedSerializer` which may in turn own more `CombinedSerializer`s which make up the full schema serializer. """ def __init__(self, schema: CoreSchema, config: CoreConfig | None = None, _use_prebuilt: bool = True) -> None: """Initializes the `SchemaSerializer`. Arguments: schema: The `CoreSchema` to use for serialization. config: Optionally a [`CoreConfig`][pydantic_core.core_schema.CoreConfig] to to configure serialization. _use_prebuilt: Whether to use pre-built validators (False during rebuilds to avoid stale references). """ def __new__(cls, schema: CoreSchema, config: CoreConfig | None = None, _use_prebuilt: bool = True) -> Self: ... def to_python( self, value: Any, *, mode: str | None = None, include: _IncEx | None = None, exclude: _IncEx | None = None, by_alias: bool | None = None, exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, exclude_computed_fields: bool = False, round_trip: bool = False, warnings: bool | Literal['none', 'warn', 'error'] = True, fallback: Callable[[Any], Any] | None = None, serialize_as_any: bool = False, polymorphic_serialization: bool | None = None, context: Any | None = None, ) -> Any: """ Serialize/marshal a Python object to a Python object including transforming and filtering data. Arguments: value: The Python object to serialize. mode: The serialization mode to use, either `'python'` or `'json'`, defaults to `'python'`. In JSON mode, all values are converted to JSON compatible types, e.g. `None`, `int`, `float`, `str`, `list`, `dict`. include: A set of fields to include, if `None` all fields are included. exclude: A set of fields to exclude, if `None` no fields are excluded. by_alias: Whether to use the alias names of fields. exclude_unset: Whether to exclude fields that are not set, e.g. are not included in `__pydantic_fields_set__`. exclude_defaults: Whether to exclude fields that are equal to their default value. exclude_none: Whether to exclude fields that have a value of `None`. exclude_computed_fields: Whether to exclude computed fields. round_trip: Whether to enable serialization and validation round-trip support. warnings: How to handle invalid fields. False/"none" ignores them, True/"warn" logs errors, "error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError]. fallback: A function to call when an unknown value is encountered, if `None` a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised. serialize_as_any: Whether to serialize fields with duck-typing serialization behavior. polymorphic_serialization: Whether to use model and dataclass polymorphic serialization for this call. context: The context to use for serialization, this is passed to functional serializers as [`info.context`][pydantic_core.core_schema.SerializationInfo.context]. Raises: PydanticSerializationError: If serialization fails and no `fallback` function is provided. Returns: The serialized Python object. """ def to_json( self, value: Any, *, indent: int | None = None, ensure_ascii: bool = False, include: _IncEx | None = None, exclude: _IncEx | None = None, by_alias: bool | None = None, exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, exclude_computed_fields: bool = False, round_trip: bool = False, warnings: bool | Literal['none', 'warn', 'error'] = True, fallback: Callable[[Any], Any] | None = None, serialize_as_any: bool = False, polymorphic_serialization: bool | None = None, context: Any | None = None, ) -> bytes: """ Serialize a Python object to JSON including transforming and filtering data. Arguments: value: The Python object to serialize. indent: If `None`, the JSON will be compact, otherwise it will be pretty-printed with the indent provided. ensure_ascii: If `True`, the output is guaranteed to have all incoming non-ASCII characters escaped. If `False` (the default), these characters will be output as-is. include: A set of fields to include, if `None` all fields are included. exclude: A set of fields to exclude, if `None` no fields are excluded. by_alias: Whether to use the alias names of fields. exclude_unset: Whether to exclude fields that are not set, e.g. are not included in `__pydantic_fields_set__`. exclude_defaults: Whether to exclude fields that are equal to their default value. exclude_none: Whether to exclude fields that have a value of `None`. exclude_computed_fields: Whether to exclude computed fields. round_trip: Whether to enable serialization and validation round-trip support. warnings: How to handle invalid fields. False/"none" ignores them, True/"warn" logs errors, "error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError]. fallback: A function to call when an unknown value is encountered, if `None` a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised. serialize_as_any: Whether to serialize fields with duck-typing serialization behavior. polymorphic_serialization: Whether to use model and dataclass polymorphic serialization for this call. context: The context to use for serialization, this is passed to functional serializers as [`info.context`][pydantic_core.core_schema.SerializationInfo.context]. Raises: PydanticSerializationError: If serialization fails and no `fallback` function is provided. Returns: JSON bytes. """ def to_json( value: Any, *, indent: int | None = None, ensure_ascii: bool = False, include: _IncEx | None = None, exclude: _IncEx | None = None, # Note: In Pydantic 2.11, the default value of `by_alias` on `SchemaSerializer` was changed from `True` to `None`, # to be consistent with the Pydantic "dump" methods. However, the default of `True` was kept here for # backwards compatibility. In Pydantic V3, `by_alias` is expected to default to `True` everywhere: by_alias: bool = True, exclude_none: bool = False, round_trip: bool = False, timedelta_mode: Literal['iso8601', 'float'] = 'iso8601', temporal_mode: Literal['iso8601', 'seconds', 'milliseconds'] = 'iso8601', bytes_mode: Literal['utf8', 'base64', 'hex'] = 'utf8', inf_nan_mode: Literal['null', 'constants', 'strings'] = 'constants', serialize_unknown: bool = False, fallback: Callable[[Any], Any] | None = None, serialize_as_any: bool = False, polymorphic_serialization: bool | None = None, context: Any | None = None, ) -> bytes: """ Serialize a Python object to JSON including transforming and filtering data. This is effectively a standalone version of [`SchemaSerializer.to_json`][pydantic_core.SchemaSerializer.to_json]. Arguments: value: The Python object to serialize. indent: If `None`, the JSON will be compact, otherwise it will be pretty-printed with the indent provided. ensure_ascii: If `True`, the output is guaranteed to have all incoming non-ASCII characters escaped. If `False` (the default), these characters will be output as-is. include: A set of fields to include, if `None` all fields are included. exclude: A set of fields to exclude, if `None` no fields are excluded. by_alias: Whether to use the alias names of fields. exclude_none: Whether to exclude fields that have a value of `None`. round_trip: Whether to enable serialization and validation round-trip support. timedelta_mode: How to serialize `timedelta` objects, either `'iso8601'` or `'float'`. temporal_mode: How to serialize datetime-like objects (`datetime`, `date`, `time`), either `'iso8601'`, `'seconds'`, or `'milliseconds'`. `iso8601` returns an ISO 8601 string; `seconds` returns the Unix timestamp in seconds as a float; `milliseconds` returns the Unix timestamp in milliseconds as a float. bytes_mode: How to serialize `bytes` objects, either `'utf8'`, `'base64'`, or `'hex'`. inf_nan_mode: How to serialize `Infinity`, `-Infinity` and `NaN` values, either `'null'`, `'constants'`, or `'strings'`. serialize_unknown: Attempt to serialize unknown types, `str(value)` will be used, if that fails `""` will be used. fallback: A function to call when an unknown value is encountered, if `None` a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised. serialize_as_any: Whether to serialize fields with duck-typing serialization behavior. polymorphic_serialization: Whether to use model and dataclass polymorphic serialization for this call. context: The context to use for serialization, this is passed to functional serializers as [`info.context`][pydantic_core.core_schema.SerializationInfo.context]. Raises: PydanticSerializationError: If serialization fails and no `fallback` function is provided. Returns: JSON bytes. """ def from_json( data: str | bytes | bytearray, *, allow_inf_nan: bool = True, cache_strings: bool | Literal['all', 'keys', 'none'] = True, allow_partial: bool | Literal['off', 'on', 'trailing-strings'] = False, ) -> Any: """ Deserialize JSON data to a Python object. This is effectively a faster version of `json.loads()`, with some extra functionality. Arguments: data: The JSON data to deserialize. allow_inf_nan: Whether to allow `Infinity`, `-Infinity` and `NaN` values as `json.loads()` does by default. cache_strings: Whether to cache strings to avoid constructing new Python objects, this should have a significant impact on performance while increasing memory usage slightly, `all/True` means cache all strings, `keys` means cache only dict keys, `none/False` means no caching. allow_partial: Whether to allow partial deserialization, if `True` JSON data is returned if the end of the input is reached before the full object is deserialized, e.g. `["aa", "bb", "c` would return `['aa', 'bb']`. `'trailing-strings'` means any final unfinished JSON string is included in the result. Raises: ValueError: If deserialization fails. Returns: The deserialized Python object. """ def to_jsonable_python( value: Any, *, include: _IncEx | None = None, exclude: _IncEx | None = None, # Note: In Pydantic 2.11, the default value of `by_alias` on `SchemaSerializer` was changed from `True` to `None`, # to be consistent with the Pydantic "dump" methods. However, the default of `True` was kept here for # backwards compatibility. In Pydantic V3, `by_alias` is expected to default to `True` everywhere: by_alias: bool = True, exclude_none: bool = False, round_trip: bool = False, timedelta_mode: Literal['iso8601', 'float'] = 'iso8601', temporal_mode: Literal['iso8601', 'seconds', 'milliseconds'] = 'iso8601', bytes_mode: Literal['utf8', 'base64', 'hex'] = 'utf8', inf_nan_mode: Literal['null', 'constants', 'strings'] = 'constants', serialize_unknown: bool = False, fallback: Callable[[Any], Any] | None = None, serialize_as_any: bool = False, polymorphic_serialization: bool | None = None, context: Any | None = None, ) -> Any: """ Serialize/marshal a Python object to a JSON-serializable Python object including transforming and filtering data. This is effectively a standalone version of [`SchemaSerializer.to_python(mode='json')`][pydantic_core.SchemaSerializer.to_python]. Args: value: The Python object to serialize. include: A set of fields to include, if `None` all fields are included. exclude: A set of fields to exclude, if `None` no fields are excluded. by_alias: Whether to use the alias names of fields. exclude_none: Whether to exclude fields that have a value of `None`. round_trip: Whether to enable serialization and validation round-trip support. timedelta_mode: How to serialize `timedelta` objects, either `'iso8601'` or `'float'`. temporal_mode: How to serialize datetime-like objects (`datetime`, `date`, `time`), either `'iso8601'`, `'seconds'`, or `'milliseconds'`. `iso8601` returns an ISO 8601 string; `seconds` returns the Unix timestamp in seconds as a float; `milliseconds` returns the Unix timestamp in milliseconds as a float. bytes_mode: How to serialize `bytes` objects, either `'utf8'`, `'base64'`, or `'hex'`. inf_nan_mode: How to serialize `Infinity`, `-Infinity` and `NaN` values, either `'null'`, `'constants'`, or `'strings'`. serialize_unknown: Attempt to serialize unknown types, `str(value)` will be used, if that fails `""` will be used. fallback: A function to call when an unknown value is encountered, if `None` a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised. serialize_as_any: Whether to serialize fields with duck-typing serialization behavior. polymorphic_serialization: Whether to use model and dataclass polymorphic serialization for this call. context: The context to use for serialization, this is passed to functional serializers as [`info.context`][pydantic_core.core_schema.SerializationInfo.context]. Raises: PydanticSerializationError: If serialization fails and no `fallback` function is provided. Returns: The serialized Python object. """ class Url(SupportsAllComparisons): """ A URL type, internal logic uses the [url rust crate](https://docs.rs/url/latest/url/) originally developed by Mozilla. """ def __init__(self, url: str) -> None: ... def __new__(cls, url: str) -> Self: ... @property def scheme(self) -> str: ... @property def username(self) -> str | None: ... @property def password(self) -> str | None: ... @property def host(self) -> str | None: ... def unicode_host(self) -> str | None: ... @property def port(self) -> int | None: ... @property def path(self) -> str | None: ... @property def query(self) -> str | None: ... def query_params(self) -> list[tuple[str, str]]: ... @property def fragment(self) -> str | None: ... def unicode_string(self) -> str: ... def __repr__(self) -> str: ... def __str__(self) -> str: ... def __deepcopy__(self, memo: dict) -> str: ... @classmethod def build( cls, *, scheme: str, username: str | None = None, password: str | None = None, host: str, port: int | None = None, path: str | None = None, query: str | None = None, fragment: str | None = None, ) -> Self: ... class MultiHostUrl(SupportsAllComparisons): """ A URL type with support for multiple hosts, as used by some databases for DSNs, e.g. `https://foo.com,bar.com/path`. Internal URL logic uses the [url rust crate](https://docs.rs/url/latest/url/) originally developed by Mozilla. """ def __init__(self, url: str) -> None: ... def __new__(cls, url: str) -> Self: ... @property def scheme(self) -> str: ... @property def path(self) -> str | None: ... @property def query(self) -> str | None: ... def query_params(self) -> list[tuple[str, str]]: ... @property def fragment(self) -> str | None: ... def hosts(self) -> list[MultiHostHost]: ... def unicode_string(self) -> str: ... def __repr__(self) -> str: ... def __str__(self) -> str: ... def __deepcopy__(self, memo: dict) -> Self: ... @classmethod def build( cls, *, scheme: str, hosts: list[MultiHostHost] | None = None, username: str | None = None, password: str | None = None, host: str | None = None, port: int | None = None, path: str | None = None, query: str | None = None, fragment: str | None = None, ) -> Self: ... @final class SchemaError(Exception): """ Information about errors that occur while building a [`SchemaValidator`][pydantic_core.SchemaValidator] or [`SchemaSerializer`][pydantic_core.SchemaSerializer]. """ def error_count(self) -> int: """ Returns: The number of errors in the schema. """ def errors(self) -> list[ErrorDetails]: """ Returns: A list of [`ErrorDetails`][pydantic_core.ErrorDetails] for each error in the schema. """ class ValidationError(ValueError): """ `ValidationError` is the exception raised by `pydantic-core` when validation fails, it contains a list of errors which detail why validation failed. """ @classmethod def from_exception_data( cls, title: str, line_errors: list[InitErrorDetails], input_type: Literal['python', 'json'] = 'python', hide_input: bool = False, ) -> Self: """ Python constructor for a Validation Error. Arguments: title: The title of the error, as used in the heading of `str(validation_error)` line_errors: A list of [`InitErrorDetails`][pydantic_core.InitErrorDetails] which contain information about errors that occurred during validation. input_type: Whether the error is for a Python object or JSON. hide_input: Whether to hide the input value in the error message. """ @property def title(self) -> str: """ The title of the error, as used in the heading of `str(validation_error)`. """ def error_count(self) -> int: """ Returns: The number of errors in the validation error. """ def errors( self, *, include_url: bool = True, include_context: bool = True, include_input: bool = True ) -> list[ErrorDetails]: """ Details about each error in the validation error. Args: include_url: Whether to include a URL to documentation on the error each error. include_context: Whether to include the context of each error. include_input: Whether to include the input value of each error. Returns: A list of [`ErrorDetails`][pydantic_core.ErrorDetails] for each error in the validation error. """ def json( self, *, indent: int | None = None, include_url: bool = True, include_context: bool = True, include_input: bool = True, ) -> str: """ Same as [`errors()`][pydantic_core.ValidationError.errors] but returns a JSON string. Args: indent: The number of spaces to indent the JSON by, or `None` for no indentation - compact JSON. include_url: Whether to include a URL to documentation on the error each error. include_context: Whether to include the context of each error. include_input: Whether to include the input value of each error. Returns: a JSON string. """ def __repr__(self) -> str: """ A string representation of the validation error. Whether or not documentation URLs are included in the repr is controlled by the environment variable `PYDANTIC_ERRORS_INCLUDE_URL` being set to `1` or `true`; by default, URLs are shown. Due to implementation details, this environment variable can only be set once, before the first validation error is created. """ class PydanticCustomError(ValueError): """A custom exception providing flexible error handling for Pydantic validators. You can raise this error in custom validators when you'd like flexibility in regards to the error type, message, and context. Example: ```py from pydantic_core import PydanticCustomError def custom_validator(v) -> None: if v <= 10: raise PydanticCustomError('custom_value_error', 'Value must be greater than {value}', {'value': 10, 'extra_context': 'extra_data'}) return v ``` Arguments: error_type: The error type. message_template: The message template. context: The data to inject into the message template. """ def __init__( self, error_type: LiteralString, message_template: LiteralString, context: dict[str, Any] | None = None, / ) -> None: ... @property def context(self) -> dict[str, Any] | None: """Values which are required to render the error message, and could hence be useful in passing error data forward.""" @property def type(self) -> str: """The error type associated with the error. For consistency with Pydantic, this is typically a snake_case string.""" @property def message_template(self) -> str: """The message template associated with the error. This is a string that can be formatted with context variables in `{curly_braces}`.""" def message(self) -> str: """The formatted message associated with the error. This presents as the message template with context variables appropriately injected.""" @final class PydanticKnownError(ValueError): """A helper class for raising exceptions that mimic Pydantic's built-in exceptions, with more flexibility in regards to context. Unlike [`PydanticCustomError`][pydantic_core.PydanticCustomError], the `error_type` argument must be a known `ErrorType`. Example: ```py from pydantic_core import PydanticKnownError def custom_validator(v) -> None: if v <= 10: raise PydanticKnownError('greater_than', {'gt': 10}) return v ``` Arguments: error_type: The error type. context: The data to inject into the message template. """ def __init__(self, error_type: ErrorType, context: dict[str, Any] | None = None, /) -> None: ... @property def context(self) -> dict[str, Any] | None: """Values which are required to render the error message, and could hence be useful in passing error data forward.""" @property def type(self) -> ErrorType: """The type of the error.""" @property def message_template(self) -> str: """The message template associated with the provided error type. This is a string that can be formatted with context variables in `{curly_braces}`.""" def message(self) -> str: """The formatted message associated with the error. This presents as the message template with context variables appropriately injected.""" @final class PydanticOmit(Exception): """An exception to signal that a field should be omitted from a generated result. This could span from omitting a field from a JSON Schema to omitting a field from a serialized result. Upcoming: more robust support for using PydanticOmit in custom serializers is still in development. Right now, this is primarily used in the JSON Schema generation process. Example: ```py from typing import Callable from pydantic_core import PydanticOmit from pydantic import BaseModel from pydantic.json_schema import GenerateJsonSchema, JsonSchemaValue class MyGenerateJsonSchema(GenerateJsonSchema): def handle_invalid_for_json_schema(self, schema, error_info) -> JsonSchemaValue: raise PydanticOmit class Predicate(BaseModel): name: str = 'no-op' func: Callable = lambda x: x instance_example = Predicate() validation_schema = instance_example.model_json_schema(schema_generator=MyGenerateJsonSchema, mode='validation') print(validation_schema) ''' {'properties': {'name': {'default': 'no-op', 'title': 'Name', 'type': 'string'}}, 'title': 'Predicate', 'type': 'object'} ''' ``` For a more in depth example / explanation, see the [customizing JSON schema](../concepts/json_schema.md#customizing-the-json-schema-generation-process) docs. """ def __new__(cls) -> Self: ... @final class PydanticUseDefault(Exception): """An exception to signal that standard validation either failed or should be skipped, and the default value should be used instead. This warning can be raised in custom validation functions to redirect the flow of validation. Example: ```py from pydantic_core import PydanticUseDefault from datetime import datetime from pydantic import BaseModel, field_validator class Event(BaseModel): name: str = 'meeting' time: datetime @field_validator('name', mode='plain') def name_must_be_present(cls, v) -> str: if not v or not isinstance(v, str): raise PydanticUseDefault() return v event1 = Event(name='party', time=datetime(2024, 1, 1, 12, 0, 0)) print(repr(event1)) # > Event(name='party', time=datetime.datetime(2024, 1, 1, 12, 0)) event2 = Event(time=datetime(2024, 1, 1, 12, 0, 0)) print(repr(event2)) # > Event(name='meeting', time=datetime.datetime(2024, 1, 1, 12, 0)) ``` For an additional example, see the [validating partial json data](../concepts/json.md#partial-json-parsing) section of the Pydantic documentation. """ def __new__(cls) -> Self: ... @final class PydanticSerializationError(ValueError): """An error raised when an issue occurs during serialization. In custom serializers, this error can be used to indicate that serialization has failed. Arguments: message: The message associated with the error. """ def __init__(self, message: str, /) -> None: ... @final class PydanticSerializationUnexpectedValue(ValueError): """An error raised when an unexpected value is encountered during serialization. This error is often caught and coerced into a warning, as `pydantic-core` generally makes a best attempt at serializing values, in contrast with validation where errors are eagerly raised. Example: ```py from pydantic import BaseModel, field_serializer from pydantic_core import PydanticSerializationUnexpectedValue class BasicPoint(BaseModel): x: int y: int @field_serializer('*') def serialize(self, v): if not isinstance(v, int): raise PydanticSerializationUnexpectedValue(f'Expected type `int`, got {type(v)} with value {v}') return v point = BasicPoint(x=1, y=2) # some sort of mutation point.x = 'a' print(point.model_dump()) ''' UserWarning: Pydantic serializer warnings: PydanticSerializationUnexpectedValue(Expected type `int`, got with value a) return self.__pydantic_serializer__.to_python( {'x': 'a', 'y': 2} ''' ``` This is often used internally in `pydantic-core` when unexpected types are encountered during serialization, but it can also be used by users in custom serializers, as seen above. Arguments: message: The message associated with the unexpected value. """ def __init__(self, message: str, /) -> None: ... @final class ArgsKwargs: """A construct used to store arguments and keyword arguments for a function call. This data structure is generally used to store information for core schemas associated with functions (like in an arguments schema). This data structure is also currently used for some validation against dataclasses. Example: ```py from pydantic.dataclasses import dataclass from pydantic import model_validator @dataclass class Model: a: int b: int @model_validator(mode="before") @classmethod def no_op_validator(cls, values): print(values) return values Model(1, b=2) #> ArgsKwargs((1,), {"b": 2}) Model(1, 2) #> ArgsKwargs((1, 2), {}) Model(a=1, b=2) #> ArgsKwargs((), {"a": 1, "b": 2}) ``` """ def __init__(self, args: tuple[Any, ...], kwargs: dict[str, Any] | None = None) -> None: """Initializes the `ArgsKwargs`. Arguments: args: The arguments (inherently ordered) for a function call. kwargs: The keyword arguments for a function call """ def __new__(cls, args: tuple[Any, ...], kwargs: dict[str, Any] | None = None) -> Self: ... @property def args(self) -> tuple[Any, ...]: """The arguments (inherently ordered) for a function call.""" @property def kwargs(self) -> dict[str, Any] | None: """The keyword arguments for a function call.""" @final class PydanticUndefinedType: """A type used as a sentinel for undefined values.""" def __copy__(self) -> Self: ... def __deepcopy__(self, memo: Any) -> Self: ... PydanticUndefined: PydanticUndefinedType def list_all_errors() -> list[ErrorTypeInfo]: """ Get information about all built-in errors. Returns: A list of `ErrorTypeInfo` typed dicts. """ @final class TzInfo(datetime.tzinfo): """An `pydantic-core` implementation of the abstract [`datetime.tzinfo`][] class.""" def __init__(self, seconds: float = 0.0) -> None: """Initializes the `TzInfo`. Arguments: seconds: The offset from UTC in seconds. Defaults to 0.0 (UTC). """ def __new__(cls, seconds: float = 0.0) -> Self: ... # Docstrings for attributes sourced from the abstract base class, [`datetime.tzinfo`](https://docs.python.org/3/library/datetime.html#datetime.tzinfo). def tzname(self, dt: datetime.datetime | None) -> str | None: """Return the time zone name corresponding to the [`datetime`][datetime.datetime] object _dt_, as a string. For more info, see [`tzinfo.tzname`][datetime.tzinfo.tzname]. """ def utcoffset(self, dt: datetime.datetime | None) -> datetime.timedelta | None: """Return offset of local time from UTC, as a [`timedelta`][datetime.timedelta] object that is positive east of UTC. If local time is west of UTC, this should be negative. More info can be found at [`tzinfo.utcoffset`][datetime.tzinfo.utcoffset]. """ def dst(self, dt: datetime.datetime | None) -> datetime.timedelta | None: """Return the daylight saving time (DST) adjustment, as a [`timedelta`][datetime.timedelta] object or `None` if DST information isn’t known. More info can be found at[`tzinfo.dst`][datetime.tzinfo.dst].""" def fromutc(self, dt: datetime.datetime) -> datetime.datetime: """Adjust the date and time data associated datetime object _dt_, returning an equivalent datetime in self’s local time. More info can be found at [`tzinfo.fromutc`][datetime.tzinfo.fromutc].""" def __deepcopy__(self, _memo: dict[Any, Any]) -> TzInfo: ... pydantic-pydantic-ba0aa01/pydantic-core/python/pydantic_core/core_schema.py000066400000000000000000004576661517143232300273650ustar00rootroot00000000000000""" This module contains definitions to build schemas which `pydantic_core` can validate and serialize. """ from __future__ import annotations as _annotations import sys import warnings from collections.abc import Generator, Hashable, Mapping from datetime import date, datetime, time, timedelta from decimal import Decimal from re import Pattern from typing import TYPE_CHECKING, Any, Callable, Literal, Union from typing_extensions import TypeVar, deprecated if sys.version_info < (3, 12): from typing_extensions import TypedDict else: from typing import TypedDict if sys.version_info < (3, 11): from typing_extensions import Protocol, Required, TypeAlias else: from typing import Protocol, Required, TypeAlias if TYPE_CHECKING: from pydantic_core import PydanticUndefined else: # The initial build of pydantic_core requires PydanticUndefined to generate # the core schema; so we need to conditionally skip it. mypy doesn't like # this at all, hence the TYPE_CHECKING branch above. try: from pydantic_core import PydanticUndefined except ImportError: PydanticUndefined = object() ExtraBehavior = Literal['allow', 'forbid', 'ignore'] class CoreConfig(TypedDict, total=False): """ Base class for schema configuration options. Attributes: title: The name of the configuration. strict: Whether the configuration should strictly adhere to specified rules. extra_fields_behavior: The behavior for handling extra fields. typed_dict_total: Whether the TypedDict should be considered total. Default is `True`. from_attributes: Whether to use attributes for models, dataclasses, and tagged union keys. loc_by_alias: Whether to use the used alias (or first alias for "field required" errors) instead of `field_names` to construct error `loc`s. Default is `True`. revalidate_instances: Whether instances of models and dataclasses should re-validate. Default is 'never'. validate_default: Whether to validate default values during validation. Default is `False`. str_max_length: The maximum length for string fields. str_min_length: The minimum length for string fields. str_strip_whitespace: Whether to strip whitespace from string fields. str_to_lower: Whether to convert string fields to lowercase. str_to_upper: Whether to convert string fields to uppercase. allow_inf_nan: Whether to allow infinity and NaN values for float fields. Default is `True`. ser_json_timedelta: The serialization option for `timedelta` values. Default is 'iso8601'. Note that if ser_json_temporal is set, then this param will be ignored. ser_json_temporal: The serialization option for datetime like values. Default is 'iso8601'. The types this covers are datetime, date, time and timedelta. If this is set, it will take precedence over ser_json_timedelta ser_json_bytes: The serialization option for `bytes` values. Default is 'utf8'. ser_json_inf_nan: The serialization option for infinity and NaN values in float fields. Default is 'null'. val_json_bytes: The validation option for `bytes` values, complementing ser_json_bytes. Default is 'utf8'. hide_input_in_errors: Whether to hide input data from `ValidationError` representation. validation_error_cause: Whether to add user-python excs to the __cause__ of a ValidationError. Requires exceptiongroup backport pre Python 3.11. coerce_numbers_to_str: Whether to enable coercion of any `Number` type to `str` (not applicable in `strict` mode). regex_engine: The regex engine to use for regex pattern validation. Default is 'rust-regex'. See `StringSchema`. cache_strings: Whether to cache strings. Default is `True`, `True` or `'all'` is required to cache strings during general validation since validators don't know if they're in a key or a value. validate_by_alias: Whether to use the field's alias when validating against the provided input data. Default is `True`. validate_by_name: Whether to use the field's name when validating against the provided input data. Default is `False`. Replacement for `populate_by_name`. serialize_by_alias: Whether to serialize by alias. Default is `False`, expected to change to `True` in V3. polymorphic_serialization: Whether to enable polymorphic serialization for models and dataclasses. Default is `False`. url_preserve_empty_path: Whether to preserve empty URL paths when validating values for a URL type. Defaults to `False`. """ title: str strict: bool # settings related to typed dicts, model fields, dataclass fields extra_fields_behavior: ExtraBehavior typed_dict_total: bool # default: True # used for models, dataclasses, and tagged union keys from_attributes: bool # whether to use the used alias (or first alias for "field required" errors) instead of field_names # to construct error `loc`s, default True loc_by_alias: bool # whether instances of models and dataclasses (including subclass instances) should re-validate, default 'never' revalidate_instances: Literal['always', 'never', 'subclass-instances'] # whether to validate default values during validation, default False validate_default: bool # used on typed-dicts and arguments # fields related to string fields only str_max_length: int str_min_length: int str_strip_whitespace: bool str_to_lower: bool str_to_upper: bool # fields related to float fields only allow_inf_nan: bool # default: True # the config options are used to customise serialization to JSON ser_json_timedelta: Literal['iso8601', 'float'] # default: 'iso8601' ser_json_temporal: Literal['iso8601', 'seconds', 'milliseconds'] # default: 'iso8601' ser_json_bytes: Literal['utf8', 'base64', 'hex'] # default: 'utf8' ser_json_inf_nan: Literal['null', 'constants', 'strings'] # default: 'null' val_json_bytes: Literal['utf8', 'base64', 'hex'] # default: 'utf8' # used to hide input data from ValidationError repr hide_input_in_errors: bool validation_error_cause: bool # default: False coerce_numbers_to_str: bool # default: False regex_engine: Literal['rust-regex', 'python-re'] # default: 'rust-regex' cache_strings: Union[bool, Literal['all', 'keys', 'none']] # default: 'True' validate_by_alias: bool # default: True validate_by_name: bool # default: False serialize_by_alias: bool # default: False polymorphic_serialization: bool # default: False url_preserve_empty_path: bool # default: False IncExCall: TypeAlias = 'set[int | str] | dict[int | str, IncExCall] | None' ContextT = TypeVar('ContextT', covariant=True, default='Any | None') class SerializationInfo(Protocol[ContextT]): """Extra data used during serialization.""" @property def include(self) -> IncExCall: """The `include` argument set during serialization.""" ... @property def exclude(self) -> IncExCall: """The `exclude` argument set during serialization.""" ... @property def context(self) -> ContextT: """The current serialization context.""" ... @property def mode(self) -> Literal['python', 'json'] | str: """The serialization mode set during serialization.""" ... @property def by_alias(self) -> bool: """The `by_alias` argument set during serialization.""" ... @property def exclude_unset(self) -> bool: """The `exclude_unset` argument set during serialization.""" ... @property def exclude_defaults(self) -> bool: """The `exclude_defaults` argument set during serialization.""" ... @property def exclude_none(self) -> bool: """The `exclude_none` argument set during serialization.""" ... @property def exclude_computed_fields(self) -> bool: """The `exclude_computed_fields` argument set during serialization.""" ... @property def serialize_as_any(self) -> bool: """The `serialize_as_any` argument set during serialization.""" ... @property def polymorphic_serialization(self) -> bool | None: """The `polymorphic_serialization` argument set during serialization, if any.""" ... @property def round_trip(self) -> bool: """The `round_trip` argument set during serialization.""" ... def mode_is_json(self) -> bool: ... def __str__(self) -> str: ... def __repr__(self) -> str: ... class FieldSerializationInfo(SerializationInfo[ContextT], Protocol): """Extra data used during field serialization.""" @property def field_name(self) -> str: """The name of the current field being serialized.""" ... class ValidationInfo(Protocol[ContextT]): """Extra data used during validation.""" @property def context(self) -> ContextT: """The current validation context.""" ... @property def config(self) -> CoreConfig | None: """The CoreConfig that applies to this validation.""" ... @property def mode(self) -> Literal['python', 'json']: """The type of input data we are currently validating.""" ... @property def data(self) -> dict[str, Any]: """The data being validated for this model.""" ... @property def field_name(self) -> str | None: """ The name of the current field being validated if this validator is attached to a model field. """ ... ExpectedSerializationTypes = Literal[ 'none', 'int', 'bool', 'float', 'str', 'bytes', 'bytearray', 'list', 'tuple', 'set', 'frozenset', 'generator', 'dict', 'datetime', 'date', 'time', 'timedelta', 'url', 'multi-host-url', 'json', 'uuid', 'any', ] class SimpleSerSchema(TypedDict, total=False): type: Required[ExpectedSerializationTypes] def simple_ser_schema(type: ExpectedSerializationTypes) -> SimpleSerSchema: """ Returns a schema for serialization with a custom type. Args: type: The type to use for serialization """ return SimpleSerSchema(type=type) # (input_value: Any, /) -> Any GeneralPlainNoInfoSerializerFunction = Callable[[Any], Any] # (input_value: Any, info: FieldSerializationInfo, /) -> Any GeneralPlainInfoSerializerFunction = Callable[[Any, SerializationInfo[Any]], Any] # (model: Any, input_value: Any, /) -> Any FieldPlainNoInfoSerializerFunction = Callable[[Any, Any], Any] # (model: Any, input_value: Any, info: FieldSerializationInfo, /) -> Any FieldPlainInfoSerializerFunction = Callable[[Any, Any, FieldSerializationInfo[Any]], Any] SerializerFunction = Union[ GeneralPlainNoInfoSerializerFunction, GeneralPlainInfoSerializerFunction, FieldPlainNoInfoSerializerFunction, FieldPlainInfoSerializerFunction, ] WhenUsed = Literal['always', 'unless-none', 'json', 'json-unless-none'] """ Values have the following meanings: * `'always'` means always use * `'unless-none'` means use unless the value is `None` * `'json'` means use when serializing to JSON * `'json-unless-none'` means use when serializing to JSON and the value is not `None` """ class PlainSerializerFunctionSerSchema(TypedDict, total=False): type: Required[Literal['function-plain']] function: Required[SerializerFunction] is_field_serializer: bool # default False info_arg: bool # default False return_schema: CoreSchema # if omitted, AnySchema is used when_used: WhenUsed # default: 'always' def plain_serializer_function_ser_schema( function: SerializerFunction, *, is_field_serializer: bool | None = None, info_arg: bool | None = None, return_schema: CoreSchema | None = None, when_used: WhenUsed = 'always', ) -> PlainSerializerFunctionSerSchema: """ Returns a schema for serialization with a function, can be either a "general" or "field" function. Args: function: The function to use for serialization is_field_serializer: Whether the serializer is for a field, e.g. takes `model` as the first argument, and `info` includes `field_name` info_arg: Whether the function takes an `info` argument return_schema: Schema to use for serializing return value when_used: When the function should be called """ if when_used == 'always': # just to avoid extra elements in schema, and to use the actual default defined in rust when_used = None # type: ignore return _dict_not_none( type='function-plain', function=function, is_field_serializer=is_field_serializer, info_arg=info_arg, return_schema=return_schema, when_used=when_used, ) class SerializerFunctionWrapHandler(Protocol): # pragma: no cover def __call__(self, input_value: Any, index_key: int | str | None = None, /) -> Any: ... # (input_value: Any, serializer: SerializerFunctionWrapHandler, /) -> Any GeneralWrapNoInfoSerializerFunction = Callable[[Any, SerializerFunctionWrapHandler], Any] # (input_value: Any, serializer: SerializerFunctionWrapHandler, info: SerializationInfo, /) -> Any GeneralWrapInfoSerializerFunction = Callable[[Any, SerializerFunctionWrapHandler, SerializationInfo[Any]], Any] # (model: Any, input_value: Any, serializer: SerializerFunctionWrapHandler, /) -> Any FieldWrapNoInfoSerializerFunction = Callable[[Any, Any, SerializerFunctionWrapHandler], Any] # (model: Any, input_value: Any, serializer: SerializerFunctionWrapHandler, info: FieldSerializationInfo, /) -> Any FieldWrapInfoSerializerFunction = Callable[[Any, Any, SerializerFunctionWrapHandler, FieldSerializationInfo[Any]], Any] WrapSerializerFunction = Union[ GeneralWrapNoInfoSerializerFunction, GeneralWrapInfoSerializerFunction, FieldWrapNoInfoSerializerFunction, FieldWrapInfoSerializerFunction, ] class WrapSerializerFunctionSerSchema(TypedDict, total=False): type: Required[Literal['function-wrap']] function: Required[WrapSerializerFunction] is_field_serializer: bool # default False info_arg: bool # default False schema: CoreSchema # if omitted, the schema on which this serializer is defined is used return_schema: CoreSchema # if omitted, AnySchema is used when_used: WhenUsed # default: 'always' def wrap_serializer_function_ser_schema( function: WrapSerializerFunction, *, is_field_serializer: bool | None = None, info_arg: bool | None = None, schema: CoreSchema | None = None, return_schema: CoreSchema | None = None, when_used: WhenUsed = 'always', ) -> WrapSerializerFunctionSerSchema: """ Returns a schema for serialization with a wrap function, can be either a "general" or "field" function. Args: function: The function to use for serialization is_field_serializer: Whether the serializer is for a field, e.g. takes `model` as the first argument, and `info` includes `field_name` info_arg: Whether the function takes an `info` argument schema: The schema to use for the inner serialization return_schema: Schema to use for serializing return value when_used: When the function should be called """ if when_used == 'always': # just to avoid extra elements in schema, and to use the actual default defined in rust when_used = None # type: ignore return _dict_not_none( type='function-wrap', function=function, is_field_serializer=is_field_serializer, info_arg=info_arg, schema=schema, return_schema=return_schema, when_used=when_used, ) class FormatSerSchema(TypedDict, total=False): type: Required[Literal['format']] formatting_string: Required[str] when_used: WhenUsed # default: 'json-unless-none' def format_ser_schema(formatting_string: str, *, when_used: WhenUsed = 'json-unless-none') -> FormatSerSchema: """ Returns a schema for serialization using python's `format` method. Args: formatting_string: String defining the format to use when_used: Same meaning as for [general_function_plain_ser_schema], but with a different default """ if when_used == 'json-unless-none': # just to avoid extra elements in schema, and to use the actual default defined in rust when_used = None # type: ignore return _dict_not_none(type='format', formatting_string=formatting_string, when_used=when_used) class ToStringSerSchema(TypedDict, total=False): type: Required[Literal['to-string']] when_used: WhenUsed # default: 'json-unless-none' def to_string_ser_schema(*, when_used: WhenUsed = 'json-unless-none') -> ToStringSerSchema: """ Returns a schema for serialization using python's `str()` / `__str__` method. Args: when_used: Same meaning as for [general_function_plain_ser_schema], but with a different default """ s = dict(type='to-string') if when_used != 'json-unless-none': # just to avoid extra elements in schema, and to use the actual default defined in rust s['when_used'] = when_used return s # type: ignore class ModelSerSchema(TypedDict, total=False): type: Required[Literal['model']] cls: Required[type[Any]] schema: Required[CoreSchema] def model_ser_schema(cls: type[Any], schema: CoreSchema) -> ModelSerSchema: """ Returns a schema for serialization using a model. Args: cls: The expected class type, used to generate warnings if the wrong type is passed schema: Internal schema to use to serialize the model dict """ return ModelSerSchema(type='model', cls=cls, schema=schema) SerSchema = Union[ SimpleSerSchema, PlainSerializerFunctionSerSchema, WrapSerializerFunctionSerSchema, FormatSerSchema, ToStringSerSchema, ModelSerSchema, ] class InvalidSchema(TypedDict, total=False): type: Required[Literal['invalid']] ref: str metadata: dict[str, Any] # note, we never plan to use this, but include it for type checking purposes to match # all other CoreSchema union members serialization: SerSchema def invalid_schema(ref: str | None = None, metadata: dict[str, Any] | None = None) -> InvalidSchema: """ Returns an invalid schema, used to indicate that a schema is invalid. Args: ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core """ return _dict_not_none(type='invalid', ref=ref, metadata=metadata) class ComputedField(TypedDict, total=False): type: Required[Literal['computed-field']] property_name: Required[str] return_schema: Required[CoreSchema] alias: str serialization_exclude_if: Callable[[Any], bool] metadata: dict[str, Any] def computed_field( property_name: str, return_schema: CoreSchema, *, alias: str | None = None, serialization_exclude_if: Callable[[Any], bool] | None = None, metadata: dict[str, Any] | None = None, ) -> ComputedField: """ ComputedFields are properties of a model or dataclass that are included in serialization. Args: property_name: The name of the property on the model or dataclass return_schema: The schema used for the type returned by the computed field alias: The name to use in the serialized output metadata: Any other information you want to include with the schema, not used by pydantic-core """ return _dict_not_none( type='computed-field', property_name=property_name, return_schema=return_schema, alias=alias, serialization_exclude_if=serialization_exclude_if, metadata=metadata, ) class AnySchema(TypedDict, total=False): type: Required[Literal['any']] ref: str metadata: dict[str, Any] serialization: SerSchema def any_schema( *, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None ) -> AnySchema: """ Returns a schema that matches any value, e.g.: ```py from pydantic_core import SchemaValidator, core_schema schema = core_schema.any_schema() v = SchemaValidator(schema) assert v.validate_python(1) == 1 ``` Args: ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none(type='any', ref=ref, metadata=metadata, serialization=serialization) class NoneSchema(TypedDict, total=False): type: Required[Literal['none']] ref: str metadata: dict[str, Any] serialization: SerSchema def none_schema( *, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None ) -> NoneSchema: """ Returns a schema that matches a None value, e.g.: ```py from pydantic_core import SchemaValidator, core_schema schema = core_schema.none_schema() v = SchemaValidator(schema) assert v.validate_python(None) is None ``` Args: ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none(type='none', ref=ref, metadata=metadata, serialization=serialization) class BoolSchema(TypedDict, total=False): type: Required[Literal['bool']] strict: bool ref: str metadata: dict[str, Any] serialization: SerSchema def bool_schema( strict: bool | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> BoolSchema: """ Returns a schema that matches a bool value, e.g.: ```py from pydantic_core import SchemaValidator, core_schema schema = core_schema.bool_schema() v = SchemaValidator(schema) assert v.validate_python('True') is True ``` Args: strict: Whether the value should be a bool or a value that can be converted to a bool ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none(type='bool', strict=strict, ref=ref, metadata=metadata, serialization=serialization) class IntSchema(TypedDict, total=False): type: Required[Literal['int']] multiple_of: int le: int ge: int lt: int gt: int strict: bool ref: str metadata: dict[str, Any] serialization: SerSchema def int_schema( *, multiple_of: int | None = None, le: int | None = None, ge: int | None = None, lt: int | None = None, gt: int | None = None, strict: bool | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> IntSchema: """ Returns a schema that matches a int value, e.g.: ```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 ``` Args: multiple_of: The value must be a multiple of this number le: The value must be less than or equal to this number ge: The value must be greater than or equal to this number lt: The value must be strictly less than this number gt: The value must be strictly greater than this number strict: Whether the value should be a int or a value that can be converted to a int ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='int', multiple_of=multiple_of, le=le, ge=ge, lt=lt, gt=gt, strict=strict, ref=ref, metadata=metadata, serialization=serialization, ) class FloatSchema(TypedDict, total=False): type: Required[Literal['float']] allow_inf_nan: bool # whether 'NaN', '+inf', '-inf' should be forbidden. default: True multiple_of: float le: float ge: float lt: float gt: float strict: bool ref: str metadata: dict[str, Any] serialization: SerSchema def float_schema( *, allow_inf_nan: bool | None = None, multiple_of: float | None = None, le: float | None = None, ge: float | None = None, lt: float | None = None, gt: float | None = None, strict: bool | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> FloatSchema: """ Returns a schema that matches a float value, e.g.: ```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 ``` Args: allow_inf_nan: Whether to allow inf and nan values multiple_of: The value must be a multiple of this number le: The value must be less than or equal to this number ge: The value must be greater than or equal to this number lt: The value must be strictly less than this number gt: The value must be strictly greater than this number strict: Whether the value should be a float or a value that can be converted to a float ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='float', allow_inf_nan=allow_inf_nan, multiple_of=multiple_of, le=le, ge=ge, lt=lt, gt=gt, strict=strict, ref=ref, metadata=metadata, serialization=serialization, ) class DecimalSchema(TypedDict, total=False): type: Required[Literal['decimal']] allow_inf_nan: bool # whether 'NaN', '+inf', '-inf' should be forbidden. default: False multiple_of: Decimal le: Decimal ge: Decimal lt: Decimal gt: Decimal max_digits: int decimal_places: int strict: bool ref: str metadata: dict[str, Any] serialization: SerSchema def decimal_schema( *, allow_inf_nan: bool | None = None, multiple_of: Decimal | None = None, le: Decimal | None = None, ge: Decimal | None = None, lt: Decimal | None = None, gt: Decimal | None = None, max_digits: int | None = None, decimal_places: int | None = None, strict: bool | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> DecimalSchema: """ Returns a schema that matches a decimal value, e.g.: ```py from decimal import Decimal from pydantic_core import SchemaValidator, core_schema schema = core_schema.decimal_schema(le=0.8, ge=0.2) v = SchemaValidator(schema) assert v.validate_python('0.5') == Decimal('0.5') ``` Args: allow_inf_nan: Whether to allow inf and nan values multiple_of: The value must be a multiple of this number le: The value must be less than or equal to this number ge: The value must be greater than or equal to this number lt: The value must be strictly less than this number gt: The value must be strictly greater than this number max_digits: The maximum number of decimal digits allowed decimal_places: The maximum number of decimal places allowed strict: Whether the value should be a float or a value that can be converted to a float ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='decimal', gt=gt, ge=ge, lt=lt, le=le, max_digits=max_digits, decimal_places=decimal_places, multiple_of=multiple_of, allow_inf_nan=allow_inf_nan, strict=strict, ref=ref, metadata=metadata, serialization=serialization, ) class ComplexSchema(TypedDict, total=False): type: Required[Literal['complex']] strict: bool ref: str metadata: dict[str, Any] serialization: SerSchema def complex_schema( *, strict: bool | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> ComplexSchema: """ Returns a schema that matches a complex value, e.g.: ```py from pydantic_core import SchemaValidator, core_schema schema = core_schema.complex_schema() v = SchemaValidator(schema) assert v.validate_python('1+2j') == complex(1, 2) assert v.validate_python(complex(1, 2)) == complex(1, 2) ``` Args: strict: Whether the value should be a complex object instance or a value that can be converted to a complex object ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='complex', strict=strict, ref=ref, metadata=metadata, serialization=serialization, ) class StringSchema(TypedDict, total=False): type: Required[Literal['str']] pattern: Union[str, Pattern[str]] max_length: int min_length: int strip_whitespace: bool to_lower: bool to_upper: bool regex_engine: Literal['rust-regex', 'python-re'] # default: 'rust-regex' strict: bool coerce_numbers_to_str: bool ref: str metadata: dict[str, Any] serialization: SerSchema def str_schema( *, pattern: str | Pattern[str] | None = None, max_length: int | None = None, min_length: int | None = None, strip_whitespace: bool | None = None, to_lower: bool | None = None, to_upper: bool | None = None, regex_engine: Literal['rust-regex', 'python-re'] | None = None, strict: bool | None = None, coerce_numbers_to_str: bool | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> StringSchema: """ Returns a schema that matches a string value, e.g.: ```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' ``` Args: pattern: A regex pattern that the value must match max_length: The value must be at most this length min_length: The value must be at least this length strip_whitespace: Whether to strip whitespace from the value to_lower: Whether to convert the value to lowercase to_upper: Whether to convert the value to uppercase regex_engine: The regex engine to use for pattern validation. Default is 'rust-regex'. - `rust-regex` uses the [`regex`](https://docs.rs/regex) Rust crate, which is non-backtracking and therefore more DDoS resistant, but does not support all regex features. - `python-re` use the [`re`](https://docs.python.org/3/library/re.html) module, which supports all regex features, but may be slower. strict: Whether the value should be a string or a value that can be converted to a string coerce_numbers_to_str: Whether to enable coercion of any `Number` type to `str` (not applicable in `strict` mode). ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='str', pattern=pattern, max_length=max_length, min_length=min_length, strip_whitespace=strip_whitespace, to_lower=to_lower, to_upper=to_upper, regex_engine=regex_engine, strict=strict, coerce_numbers_to_str=coerce_numbers_to_str, ref=ref, metadata=metadata, serialization=serialization, ) class BytesSchema(TypedDict, total=False): type: Required[Literal['bytes']] max_length: int min_length: int strict: bool ref: str metadata: dict[str, Any] serialization: SerSchema def bytes_schema( *, max_length: int | None = None, min_length: int | None = None, strict: bool | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> BytesSchema: """ Returns a schema that matches a bytes value, e.g.: ```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' ``` Args: max_length: The value must be at most this length min_length: The value must be at least this length strict: Whether the value should be a bytes or a value that can be converted to a bytes ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='bytes', max_length=max_length, min_length=min_length, strict=strict, ref=ref, metadata=metadata, serialization=serialization, ) class DateSchema(TypedDict, total=False): type: Required[Literal['date']] strict: bool le: date ge: date lt: date gt: date now_op: Literal['past', 'future'] # defaults to current local utc offset from `time.localtime().tm_gmtoff` # value is restricted to -86_400 < offset < 86_400: now_utc_offset: int ref: str metadata: dict[str, Any] serialization: SerSchema def date_schema( *, strict: bool | None = None, le: date | None = None, ge: date | None = None, lt: date | None = None, gt: date | None = None, now_op: Literal['past', 'future'] | None = None, now_utc_offset: int | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> DateSchema: """ Returns a schema that matches a date value, e.g.: ```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) ``` Args: strict: Whether the value should be a date or a value that can be converted to a date le: The value must be less than or equal to this date ge: The value must be greater than or equal to this date lt: The value must be strictly less than this date gt: The value must be strictly greater than this date now_op: The value must be in the past or future relative to the current date now_utc_offset: The value must be in the past or future relative to the current date with this utc offset ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='date', strict=strict, le=le, ge=ge, lt=lt, gt=gt, now_op=now_op, now_utc_offset=now_utc_offset, ref=ref, metadata=metadata, serialization=serialization, ) class TimeSchema(TypedDict, total=False): type: Required[Literal['time']] strict: bool le: time ge: time lt: time gt: time tz_constraint: Union[Literal['aware', 'naive'], int] microseconds_precision: Literal['truncate', 'error'] ref: str metadata: dict[str, Any] serialization: SerSchema def time_schema( *, strict: bool | None = None, le: time | None = None, ge: time | None = None, lt: time | None = None, gt: time | None = None, tz_constraint: Literal['aware', 'naive'] | int | None = None, microseconds_precision: Literal['truncate', 'error'] = 'truncate', ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> TimeSchema: """ Returns a schema that matches a time value, e.g.: ```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) ``` Args: strict: Whether the value should be a time or a value that can be converted to a time le: The value must be less than or equal to this time ge: The value must be greater than or equal to this time lt: The value must be strictly less than this time gt: The value must be strictly greater than this time tz_constraint: The value must be timezone aware or naive, or an int to indicate required tz offset microseconds_precision: The behavior when seconds have more than 6 digits or microseconds is too large ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='time', strict=strict, le=le, ge=ge, lt=lt, gt=gt, tz_constraint=tz_constraint, microseconds_precision=microseconds_precision, ref=ref, metadata=metadata, serialization=serialization, ) class DatetimeSchema(TypedDict, total=False): type: Required[Literal['datetime']] strict: bool le: datetime ge: datetime lt: datetime gt: datetime now_op: Literal['past', 'future'] tz_constraint: Union[Literal['aware', 'naive'], int] # defaults to current local utc offset from `time.localtime().tm_gmtoff` # value is restricted to -86_400 < offset < 86_400 by bounds in generate_self_schema.py now_utc_offset: int microseconds_precision: Literal['truncate', 'error'] # default: 'truncate' ref: str metadata: dict[str, Any] serialization: SerSchema def datetime_schema( *, strict: bool | None = None, le: datetime | None = None, ge: datetime | None = None, lt: datetime | None = None, gt: datetime | None = None, now_op: Literal['past', 'future'] | None = None, tz_constraint: Literal['aware', 'naive'] | int | None = None, now_utc_offset: int | None = None, microseconds_precision: Literal['truncate', 'error'] = 'truncate', ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> DatetimeSchema: """ Returns a schema that matches a datetime value, e.g.: ```py from datetime import datetime from pydantic_core import SchemaValidator, core_schema schema = core_schema.datetime_schema() v = SchemaValidator(schema) now = datetime.now() assert v.validate_python(str(now)) == now ``` Args: strict: Whether the value should be a datetime or a value that can be converted to a datetime le: The value must be less than or equal to this datetime ge: The value must be greater than or equal to this datetime lt: The value must be strictly less than this datetime gt: The value must be strictly greater than this datetime now_op: The value must be in the past or future relative to the current datetime tz_constraint: The value must be timezone aware or naive, or an int to indicate required tz offset TODO: use of a tzinfo where offset changes based on the datetime is not yet supported now_utc_offset: The value must be in the past or future relative to the current datetime with this utc offset microseconds_precision: The behavior when seconds have more than 6 digits or microseconds is too large ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='datetime', strict=strict, le=le, ge=ge, lt=lt, gt=gt, now_op=now_op, tz_constraint=tz_constraint, now_utc_offset=now_utc_offset, microseconds_precision=microseconds_precision, ref=ref, metadata=metadata, serialization=serialization, ) class TimedeltaSchema(TypedDict, total=False): type: Required[Literal['timedelta']] strict: bool le: timedelta ge: timedelta lt: timedelta gt: timedelta microseconds_precision: Literal['truncate', 'error'] ref: str metadata: dict[str, Any] serialization: SerSchema def timedelta_schema( *, strict: bool | None = None, le: timedelta | None = None, ge: timedelta | None = None, lt: timedelta | None = None, gt: timedelta | None = None, microseconds_precision: Literal['truncate', 'error'] = 'truncate', ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> TimedeltaSchema: """ Returns a schema that matches a timedelta value, e.g.: ```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) ``` Args: strict: Whether the value should be a timedelta or a value that can be converted to a timedelta le: The value must be less than or equal to this timedelta ge: The value must be greater than or equal to this timedelta lt: The value must be strictly less than this timedelta gt: The value must be strictly greater than this timedelta microseconds_precision: The behavior when seconds have more than 6 digits or microseconds is too large ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='timedelta', strict=strict, le=le, ge=ge, lt=lt, gt=gt, microseconds_precision=microseconds_precision, ref=ref, metadata=metadata, serialization=serialization, ) class LiteralSchema(TypedDict, total=False): type: Required[Literal['literal']] expected: Required[list[Any]] ref: str metadata: dict[str, Any] serialization: SerSchema def literal_schema( expected: list[Any], *, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> LiteralSchema: """ Returns a schema that matches a literal value, e.g.: ```py from pydantic_core import SchemaValidator, core_schema schema = core_schema.literal_schema(['hello', 'world']) v = SchemaValidator(schema) assert v.validate_python('hello') == 'hello' ``` Args: expected: The value must be one of these values ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none(type='literal', expected=expected, ref=ref, metadata=metadata, serialization=serialization) class EnumSchema(TypedDict, total=False): type: Required[Literal['enum']] cls: Required[Any] members: Required[list[Any]] sub_type: Literal['str', 'int', 'float'] missing: Callable[[Any], Any] strict: bool ref: str metadata: dict[str, Any] serialization: SerSchema def enum_schema( cls: Any, members: list[Any], *, sub_type: Literal['str', 'int', 'float'] | None = None, missing: Callable[[Any], Any] | None = None, strict: bool | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> EnumSchema: """ Returns a schema that matches an enum value, e.g.: ```py from enum import Enum from pydantic_core import SchemaValidator, core_schema class Color(Enum): RED = 1 GREEN = 2 BLUE = 3 schema = core_schema.enum_schema(Color, list(Color.__members__.values())) v = SchemaValidator(schema) assert v.validate_python(2) is Color.GREEN ``` Args: cls: The enum class members: The members of the enum, generally `list(MyEnum.__members__.values())` sub_type: The type of the enum, either 'str' or 'int' or None for plain enums missing: A function to use when the value is not found in the enum, from `_missing_` strict: Whether to use strict mode, defaults to False ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='enum', cls=cls, members=members, sub_type=sub_type, missing=missing, strict=strict, ref=ref, metadata=metadata, serialization=serialization, ) class MissingSentinelSchema(TypedDict, total=False): type: Required[Literal['missing-sentinel']] metadata: dict[str, Any] serialization: SerSchema def missing_sentinel_schema( metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> MissingSentinelSchema: """Returns a schema for the `MISSING` sentinel.""" return _dict_not_none( type='missing-sentinel', metadata=metadata, serialization=serialization, ) # must match input/parse_json.rs::JsonType::try_from JsonType = Literal['null', 'bool', 'int', 'float', 'str', 'list', 'dict'] class IsInstanceSchema(TypedDict, total=False): type: Required[Literal['is-instance']] cls: Required[Any] cls_repr: str ref: str metadata: dict[str, Any] serialization: SerSchema def is_instance_schema( cls: Any, *, cls_repr: str | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> IsInstanceSchema: """ Returns a schema that checks if a value is an instance of a class, equivalent to python's `isinstance` method, e.g.: ```py from pydantic_core import SchemaValidator, core_schema class A: pass schema = core_schema.is_instance_schema(cls=A) v = SchemaValidator(schema) v.validate_python(A()) ``` Args: cls: The value must be an instance of this class cls_repr: If provided this string is used in the validator name instead of `repr(cls)` ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='is-instance', cls=cls, cls_repr=cls_repr, ref=ref, metadata=metadata, serialization=serialization ) class IsSubclassSchema(TypedDict, total=False): type: Required[Literal['is-subclass']] cls: Required[type[Any]] cls_repr: str ref: str metadata: dict[str, Any] serialization: SerSchema def is_subclass_schema( cls: type[Any], *, cls_repr: str | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> IsInstanceSchema: """ Returns a schema that checks if a value is a subtype of a class, equivalent to python's `issubclass` method, e.g.: ```py from pydantic_core import SchemaValidator, core_schema class A: pass class B(A): pass schema = core_schema.is_subclass_schema(cls=A) v = SchemaValidator(schema) v.validate_python(B) ``` Args: cls: The value must be a subclass of this class cls_repr: If provided this string is used in the validator name instead of `repr(cls)` ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='is-subclass', cls=cls, cls_repr=cls_repr, ref=ref, metadata=metadata, serialization=serialization ) class CallableSchema(TypedDict, total=False): type: Required[Literal['callable']] ref: str metadata: dict[str, Any] serialization: SerSchema def callable_schema( *, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None ) -> CallableSchema: """ Returns a schema that checks if a value is callable, equivalent to python's `callable` method, e.g.: ```py from pydantic_core import SchemaValidator, core_schema schema = core_schema.callable_schema() v = SchemaValidator(schema) v.validate_python(min) ``` Args: ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none(type='callable', ref=ref, metadata=metadata, serialization=serialization) class UuidSchema(TypedDict, total=False): type: Required[Literal['uuid']] version: Literal[1, 3, 4, 5, 7] strict: bool ref: str metadata: dict[str, Any] serialization: SerSchema def uuid_schema( *, version: Literal[1, 3, 4, 5, 6, 7, 8] | None = None, strict: bool | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> UuidSchema: return _dict_not_none( type='uuid', version=version, strict=strict, ref=ref, metadata=metadata, serialization=serialization ) class IncExSeqSerSchema(TypedDict, total=False): type: Required[Literal['include-exclude-sequence']] include: set[int] exclude: set[int] def filter_seq_schema(*, include: set[int] | None = None, exclude: set[int] | None = None) -> IncExSeqSerSchema: return _dict_not_none(type='include-exclude-sequence', include=include, exclude=exclude) IncExSeqOrElseSerSchema = Union[IncExSeqSerSchema, SerSchema] class ListSchema(TypedDict, total=False): type: Required[Literal['list']] items_schema: CoreSchema min_length: int max_length: int fail_fast: bool strict: bool ref: str metadata: dict[str, Any] serialization: IncExSeqOrElseSerSchema def list_schema( items_schema: CoreSchema | None = None, *, min_length: int | None = None, max_length: int | None = None, fail_fast: bool | None = None, strict: bool | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: IncExSeqOrElseSerSchema | None = None, ) -> ListSchema: """ Returns a schema that matches a list value, e.g.: ```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] ``` Args: items_schema: The value must be a list of items that match this schema min_length: The value must be a list with at least this many items max_length: The value must be a list with at most this many items fail_fast: Stop validation on the first error strict: The value must be a list with exactly this many items ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='list', items_schema=items_schema, min_length=min_length, max_length=max_length, fail_fast=fail_fast, strict=strict, ref=ref, metadata=metadata, serialization=serialization, ) # @deprecated('tuple_positional_schema is deprecated. Use pydantic_core.core_schema.tuple_schema instead.') def tuple_positional_schema( items_schema: list[CoreSchema], *, extras_schema: CoreSchema | None = None, strict: bool | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: IncExSeqOrElseSerSchema | None = None, ) -> TupleSchema: """ Returns a schema that matches a tuple of schemas, e.g.: ```py from pydantic_core import SchemaValidator, core_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') ``` Args: items_schema: The value must be a tuple with items that match these schemas extras_schema: The value must be a tuple with items that match this schema This was inspired by JSON schema's `prefixItems` and `items` fields. In python's `typing.Tuple`, you can't specify a type for "extra" items -- they must all be the same type if the length is variable. So this field won't be set from a `typing.Tuple` annotation on a pydantic model. strict: The value must be a tuple with exactly this many items ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ if extras_schema is not None: variadic_item_index = len(items_schema) items_schema = items_schema + [extras_schema] else: variadic_item_index = None return tuple_schema( items_schema=items_schema, variadic_item_index=variadic_item_index, strict=strict, ref=ref, metadata=metadata, serialization=serialization, ) # @deprecated('tuple_variable_schema is deprecated. Use pydantic_core.core_schema.tuple_schema instead.') def tuple_variable_schema( items_schema: CoreSchema | None = None, *, min_length: int | None = None, max_length: int | None = None, strict: bool | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: IncExSeqOrElseSerSchema | None = None, ) -> TupleSchema: """ Returns a schema that matches a tuple of a given schema, e.g.: ```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 ) v = SchemaValidator(schema) assert v.validate_python(('1', 2, 3)) == (1, 2, 3) ``` Args: items_schema: The value must be a tuple with items that match this schema min_length: The value must be a tuple with at least this many items max_length: The value must be a tuple with at most this many items strict: The value must be a tuple with exactly this many items ref: Optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return tuple_schema( items_schema=[items_schema or any_schema()], variadic_item_index=0, min_length=min_length, max_length=max_length, strict=strict, ref=ref, metadata=metadata, serialization=serialization, ) class TupleSchema(TypedDict, total=False): type: Required[Literal['tuple']] items_schema: Required[list[CoreSchema]] variadic_item_index: int min_length: int max_length: int fail_fast: bool strict: bool ref: str metadata: dict[str, Any] serialization: IncExSeqOrElseSerSchema def tuple_schema( items_schema: list[CoreSchema], *, variadic_item_index: int | None = None, min_length: int | None = None, max_length: int | None = None, fail_fast: bool | None = None, strict: bool | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: IncExSeqOrElseSerSchema | None = None, ) -> TupleSchema: """ Returns a schema that matches a tuple of schemas, with an optional variadic item, e.g.: ```py from pydantic_core import SchemaValidator, core_schema schema = core_schema.tuple_schema( [core_schema.int_schema(), core_schema.str_schema(), core_schema.float_schema()], variadic_item_index=1, ) v = SchemaValidator(schema) assert v.validate_python((1, 'hello', 'world', 1.5)) == (1, 'hello', 'world', 1.5) ``` Args: items_schema: The value must be a tuple with items that match these schemas variadic_item_index: The index of the schema in `items_schema` to be treated as variadic (following PEP 646) min_length: The value must be a tuple with at least this many items max_length: The value must be a tuple with at most this many items fail_fast: Stop validation on the first error strict: The value must be a tuple with exactly this many items ref: Optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='tuple', items_schema=items_schema, variadic_item_index=variadic_item_index, min_length=min_length, max_length=max_length, fail_fast=fail_fast, strict=strict, ref=ref, metadata=metadata, serialization=serialization, ) class SetSchema(TypedDict, total=False): type: Required[Literal['set']] items_schema: CoreSchema min_length: int max_length: int fail_fast: bool strict: bool ref: str metadata: dict[str, Any] serialization: SerSchema def set_schema( items_schema: CoreSchema | None = None, *, min_length: int | None = None, max_length: int | None = None, fail_fast: bool | None = None, strict: bool | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> SetSchema: """ Returns a schema that matches a set of a given schema, e.g.: ```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 ) v = SchemaValidator(schema) assert v.validate_python({1, '2', 3}) == {1, 2, 3} ``` Args: items_schema: The value must be a set with items that match this schema min_length: The value must be a set with at least this many items max_length: The value must be a set with at most this many items fail_fast: Stop validation on the first error strict: The value must be a set with exactly this many items ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='set', items_schema=items_schema, min_length=min_length, max_length=max_length, fail_fast=fail_fast, strict=strict, ref=ref, metadata=metadata, serialization=serialization, ) class FrozenSetSchema(TypedDict, total=False): type: Required[Literal['frozenset']] items_schema: CoreSchema min_length: int max_length: int fail_fast: bool strict: bool ref: str metadata: dict[str, Any] serialization: SerSchema def frozenset_schema( items_schema: CoreSchema | None = None, *, min_length: int | None = None, max_length: int | None = None, fail_fast: bool | None = None, strict: bool | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> FrozenSetSchema: """ Returns a schema that matches a frozenset of a given schema, e.g.: ```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 ) v = SchemaValidator(schema) assert v.validate_python(frozenset(range(3))) == frozenset({0, 1, 2}) ``` Args: items_schema: The value must be a frozenset with items that match this schema min_length: The value must be a frozenset with at least this many items max_length: The value must be a frozenset with at most this many items fail_fast: Stop validation on the first error strict: The value must be a frozenset with exactly this many items ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='frozenset', items_schema=items_schema, min_length=min_length, max_length=max_length, fail_fast=fail_fast, strict=strict, ref=ref, metadata=metadata, serialization=serialization, ) class GeneratorSchema(TypedDict, total=False): type: Required[Literal['generator']] items_schema: CoreSchema min_length: int max_length: int ref: str metadata: dict[str, Any] serialization: IncExSeqOrElseSerSchema def generator_schema( items_schema: CoreSchema | None = None, *, min_length: int | None = None, max_length: int | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: IncExSeqOrElseSerSchema | None = None, ) -> GeneratorSchema: """ Returns a schema that matches a generator value, e.g.: ```py from typing import Iterator from pydantic_core import SchemaValidator, core_schema def gen() -> Iterator[int]: yield 1 schema = core_schema.generator_schema(items_schema=core_schema.int_schema()) v = SchemaValidator(schema) v.validate_python(gen()) ``` Unlike other types, validated generators do not raise ValidationErrors eagerly, but instead will raise a ValidationError when a violating value is actually read from the generator. This is to ensure that "validated" generators retain the benefit of lazy evaluation. Args: items_schema: The value must be a generator with items that match this schema min_length: The value must be a generator that yields at least this many items max_length: The value must be a generator that yields at most this many items ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='generator', items_schema=items_schema, min_length=min_length, max_length=max_length, ref=ref, metadata=metadata, serialization=serialization, ) IncExDict = set[Union[int, str]] class IncExDictSerSchema(TypedDict, total=False): type: Required[Literal['include-exclude-dict']] include: IncExDict exclude: IncExDict def filter_dict_schema(*, include: IncExDict | None = None, exclude: IncExDict | None = None) -> IncExDictSerSchema: return _dict_not_none(type='include-exclude-dict', include=include, exclude=exclude) IncExDictOrElseSerSchema = Union[IncExDictSerSchema, SerSchema] class DictSchema(TypedDict, total=False): type: Required[Literal['dict']] keys_schema: CoreSchema # default: AnySchema values_schema: CoreSchema # default: AnySchema min_length: int max_length: int fail_fast: bool strict: bool ref: str metadata: dict[str, Any] serialization: IncExDictOrElseSerSchema def dict_schema( keys_schema: CoreSchema | None = None, values_schema: CoreSchema | None = None, *, min_length: int | None = None, max_length: int | None = None, fail_fast: bool | None = None, strict: bool | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> DictSchema: """ Returns a schema that matches a dict value, e.g.: ```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() ) v = SchemaValidator(schema) assert v.validate_python({'a': '1', 'b': 2}) == {'a': 1, 'b': 2} ``` Args: keys_schema: The value must be a dict with keys that match this schema values_schema: The value must be a dict with values that match this schema min_length: The value must be a dict with at least this many items max_length: The value must be a dict with at most this many items fail_fast: Stop validation on the first error strict: Whether the keys and values should be validated with strict mode ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='dict', keys_schema=keys_schema, values_schema=values_schema, min_length=min_length, max_length=max_length, fail_fast=fail_fast, strict=strict, ref=ref, metadata=metadata, serialization=serialization, ) # (input_value: Any, /) -> Any NoInfoValidatorFunction = Callable[[Any], Any] class NoInfoValidatorFunctionSchema(TypedDict): type: Literal['no-info'] function: NoInfoValidatorFunction # (input_value: Any, info: ValidationInfo, /) -> Any WithInfoValidatorFunction = Callable[[Any, ValidationInfo[Any]], Any] class WithInfoValidatorFunctionSchema(TypedDict, total=False): type: Required[Literal['with-info']] function: Required[WithInfoValidatorFunction] field_name: str # deprecated ValidationFunction = Union[NoInfoValidatorFunctionSchema, WithInfoValidatorFunctionSchema] class _ValidatorFunctionSchema(TypedDict, total=False): function: Required[ValidationFunction] schema: Required[CoreSchema] ref: str metadata: dict[str, Any] serialization: SerSchema class BeforeValidatorFunctionSchema(_ValidatorFunctionSchema, total=False): type: Required[Literal['function-before']] json_schema_input_schema: CoreSchema def no_info_before_validator_function( function: NoInfoValidatorFunction, schema: CoreSchema, *, ref: str | None = None, json_schema_input_schema: CoreSchema | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> BeforeValidatorFunctionSchema: """ Returns a schema that calls a validator function before validating, no `info` argument is provided, e.g.: ```py from pydantic_core import SchemaValidator, core_schema def fn(v: bytes) -> str: return v.decode() + 'world' func_schema = core_schema.no_info_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'} ``` Args: function: The validator function to call schema: The schema to validate the output of the validator function ref: optional unique identifier of the schema, used to reference the schema in other places json_schema_input_schema: The core schema to be used to generate the corresponding JSON Schema input type metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='function-before', function={'type': 'no-info', 'function': function}, schema=schema, ref=ref, json_schema_input_schema=json_schema_input_schema, metadata=metadata, serialization=serialization, ) def with_info_before_validator_function( function: WithInfoValidatorFunction, schema: CoreSchema, *, field_name: str | None = None, ref: str | None = None, json_schema_input_schema: CoreSchema | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> BeforeValidatorFunctionSchema: """ Returns a schema that calls a validator function before validation, the function is called with an `info` argument, e.g.: ```py from pydantic_core import SchemaValidator, core_schema def fn(v: bytes, info: core_schema.ValidationInfo) -> str: assert info.data is not None assert info.field_name is not None return v.decode() + 'world' func_schema = core_schema.with_info_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'} ``` Args: function: The validator function to call field_name: The name of the field this validator is applied to, if any (deprecated) schema: The schema to validate the output of the validator function ref: optional unique identifier of the schema, used to reference the schema in other places json_schema_input_schema: The core schema to be used to generate the corresponding JSON Schema input type metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ if field_name is not None: warnings.warn( 'The `field_name` argument on `with_info_before_validator_function` is deprecated, it will be passed to the function through `ValidationState` instead.', DeprecationWarning, stacklevel=2, ) return _dict_not_none( type='function-before', function=_dict_not_none(type='with-info', function=function, field_name=field_name), schema=schema, ref=ref, json_schema_input_schema=json_schema_input_schema, metadata=metadata, serialization=serialization, ) class AfterValidatorFunctionSchema(_ValidatorFunctionSchema, total=False): type: Required[Literal['function-after']] def no_info_after_validator_function( function: NoInfoValidatorFunction, schema: CoreSchema, *, ref: str | None = None, json_schema_input_schema: CoreSchema | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> AfterValidatorFunctionSchema: """ Returns a schema that calls a validator function after validating, no `info` argument is provided, e.g.: ```py from pydantic_core import SchemaValidator, core_schema def fn(v: str) -> str: return v + 'world' func_schema = core_schema.no_info_after_validator_function(fn, 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'} ``` Args: function: The validator function to call after the schema is validated schema: The schema to validate before the validator function ref: optional unique identifier of the schema, used to reference the schema in other places json_schema_input_schema: The core schema to be used to generate the corresponding JSON Schema input type metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='function-after', function={'type': 'no-info', 'function': function}, schema=schema, ref=ref, json_schema_input_schema=json_schema_input_schema, metadata=metadata, serialization=serialization, ) def with_info_after_validator_function( function: WithInfoValidatorFunction, schema: CoreSchema, *, field_name: str | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> AfterValidatorFunctionSchema: """ Returns a schema that calls a validator function after validation, the function is called with an `info` argument, e.g.: ```py from pydantic_core import SchemaValidator, core_schema def fn(v: str, info: core_schema.ValidationInfo) -> str: assert info.data is not None assert info.field_name is not None return v + 'world' func_schema = core_schema.with_info_after_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'} ``` Args: function: The validator function to call after the schema is validated schema: The schema to validate before the validator function field_name: The name of the field this validator is applied to, if any (deprecated) ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ if field_name is not None: warnings.warn( 'The `field_name` argument on `with_info_after_validator_function` is deprecated, it will be passed to the function through `ValidationState` instead.', DeprecationWarning, stacklevel=2, ) return _dict_not_none( type='function-after', function=_dict_not_none(type='with-info', function=function, field_name=field_name), schema=schema, ref=ref, metadata=metadata, serialization=serialization, ) class ValidatorFunctionWrapHandler(Protocol): def __call__(self, input_value: Any, outer_location: str | int | None = None, /) -> Any: # pragma: no cover ... # (input_value: Any, validator: ValidatorFunctionWrapHandler, /) -> Any NoInfoWrapValidatorFunction = Callable[[Any, ValidatorFunctionWrapHandler], Any] class NoInfoWrapValidatorFunctionSchema(TypedDict): type: Literal['no-info'] function: NoInfoWrapValidatorFunction # (input_value: Any, validator: ValidatorFunctionWrapHandler, info: ValidationInfo, /) -> Any WithInfoWrapValidatorFunction = Callable[[Any, ValidatorFunctionWrapHandler, ValidationInfo[Any]], Any] class WithInfoWrapValidatorFunctionSchema(TypedDict, total=False): type: Required[Literal['with-info']] function: Required[WithInfoWrapValidatorFunction] field_name: str # deprecated WrapValidatorFunction = Union[NoInfoWrapValidatorFunctionSchema, WithInfoWrapValidatorFunctionSchema] class WrapValidatorFunctionSchema(TypedDict, total=False): type: Required[Literal['function-wrap']] function: Required[WrapValidatorFunction] schema: Required[CoreSchema] ref: str json_schema_input_schema: CoreSchema metadata: dict[str, Any] serialization: SerSchema def no_info_wrap_validator_function( function: NoInfoWrapValidatorFunction, schema: CoreSchema, *, ref: str | None = None, json_schema_input_schema: CoreSchema | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> WrapValidatorFunctionSchema: """ Returns a schema which calls a function with a `validator` callable argument which can optionally be used to call inner validation with the function logic, this is much like the "onion" implementation of middleware in many popular web frameworks, no `info` argument is passed, e.g.: ```py from pydantic_core import SchemaValidator, core_schema def fn( v: str, validator: core_schema.ValidatorFunctionWrapHandler, ) -> str: return validator(input_value=v) + 'world' schema = core_schema.no_info_wrap_validator_function( function=fn, schema=core_schema.str_schema() ) v = SchemaValidator(schema) assert v.validate_python('hello ') == 'hello world' ``` Args: function: The validator function to call schema: The schema to validate the output of the validator function ref: optional unique identifier of the schema, used to reference the schema in other places json_schema_input_schema: The core schema to be used to generate the corresponding JSON Schema input type metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='function-wrap', function={'type': 'no-info', 'function': function}, schema=schema, json_schema_input_schema=json_schema_input_schema, ref=ref, metadata=metadata, serialization=serialization, ) def with_info_wrap_validator_function( function: WithInfoWrapValidatorFunction, schema: CoreSchema, *, field_name: str | None = None, json_schema_input_schema: CoreSchema | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> WrapValidatorFunctionSchema: """ Returns a schema which calls a function with a `validator` callable argument which can optionally be used to call inner validation with the function logic, this is much like the "onion" implementation of middleware in many popular web frameworks, an `info` argument is also passed, e.g.: ```py from pydantic_core import SchemaValidator, core_schema def fn( v: str, validator: core_schema.ValidatorFunctionWrapHandler, info: core_schema.ValidationInfo, ) -> str: return validator(input_value=v) + 'world' schema = core_schema.with_info_wrap_validator_function( function=fn, schema=core_schema.str_schema() ) v = SchemaValidator(schema) assert v.validate_python('hello ') == 'hello world' ``` Args: function: The validator function to call schema: The schema to validate the output of the validator function field_name: The name of the field this validator is applied to, if any (deprecated) json_schema_input_schema: The core schema to be used to generate the corresponding JSON Schema input type ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ if field_name is not None: warnings.warn( 'The `field_name` argument on `with_info_wrap_validator_function` is deprecated, it will be passed to the function through `ValidationState` instead.', DeprecationWarning, stacklevel=2, ) return _dict_not_none( type='function-wrap', function=_dict_not_none(type='with-info', function=function, field_name=field_name), schema=schema, json_schema_input_schema=json_schema_input_schema, ref=ref, metadata=metadata, serialization=serialization, ) class PlainValidatorFunctionSchema(TypedDict, total=False): type: Required[Literal['function-plain']] function: Required[ValidationFunction] ref: str json_schema_input_schema: CoreSchema metadata: dict[str, Any] serialization: SerSchema def no_info_plain_validator_function( function: NoInfoValidatorFunction, *, ref: str | None = None, json_schema_input_schema: CoreSchema | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> PlainValidatorFunctionSchema: """ Returns a schema that uses the provided function for validation, no `info` argument is passed, e.g.: ```py from pydantic_core import SchemaValidator, core_schema def fn(v: str) -> str: assert 'hello' in v return v + 'world' schema = core_schema.no_info_plain_validator_function(function=fn) v = SchemaValidator(schema) assert v.validate_python('hello ') == 'hello world' ``` Args: function: The validator function to call ref: optional unique identifier of the schema, used to reference the schema in other places json_schema_input_schema: The core schema to be used to generate the corresponding JSON Schema input type metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='function-plain', function={'type': 'no-info', 'function': function}, ref=ref, json_schema_input_schema=json_schema_input_schema, metadata=metadata, serialization=serialization, ) def with_info_plain_validator_function( function: WithInfoValidatorFunction, *, field_name: str | None = None, ref: str | None = None, json_schema_input_schema: CoreSchema | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> PlainValidatorFunctionSchema: """ Returns a schema that uses the provided function for validation, an `info` argument is passed, e.g.: ```py from pydantic_core import SchemaValidator, core_schema def fn(v: str, info: core_schema.ValidationInfo) -> str: assert 'hello' in v return v + 'world' schema = core_schema.with_info_plain_validator_function(function=fn) v = SchemaValidator(schema) assert v.validate_python('hello ') == 'hello world' ``` Args: function: The validator function to call field_name: The name of the field this validator is applied to, if any (deprecated) ref: optional unique identifier of the schema, used to reference the schema in other places json_schema_input_schema: The core schema to be used to generate the corresponding JSON Schema input type metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ if field_name is not None: warnings.warn( 'The `field_name` argument on `with_info_plain_validator_function` is deprecated, it will be passed to the function through `ValidationState` instead.', DeprecationWarning, stacklevel=2, ) return _dict_not_none( type='function-plain', function=_dict_not_none(type='with-info', function=function, field_name=field_name), ref=ref, json_schema_input_schema=json_schema_input_schema, metadata=metadata, serialization=serialization, ) class WithDefaultSchema(TypedDict, total=False): type: Required[Literal['default']] schema: Required[CoreSchema] default: Any default_factory: Union[Callable[[], Any], Callable[[dict[str, Any]], Any]] default_factory_takes_data: bool on_error: Literal['raise', 'omit', 'default'] # default: 'raise' validate_default: bool # default: False strict: bool ref: str metadata: dict[str, Any] serialization: SerSchema def with_default_schema( schema: CoreSchema, *, default: Any = PydanticUndefined, default_factory: Union[Callable[[], Any], Callable[[dict[str, Any]], Any], None] = None, default_factory_takes_data: bool | None = None, on_error: Literal['raise', 'omit', 'default'] | None = None, validate_default: bool | None = None, strict: bool | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> WithDefaultSchema: """ Returns a schema that adds a default value to the given schema, e.g.: ```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)} ) v = SchemaValidator(wrapper_schema) assert v.validate_python({}) == v.validate_python({'a': 'hello'}) ``` Args: schema: The schema to add a default value to default: The default value to use default_factory: A callable that returns the default value to use default_factory_takes_data: Whether the default factory takes a validated data argument on_error: What to do if the schema validation fails. One of 'raise', 'omit', 'default' validate_default: Whether the default value should be validated strict: Whether the underlying schema should be validated with strict mode ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ s = _dict_not_none( type='default', schema=schema, default_factory=default_factory, default_factory_takes_data=default_factory_takes_data, on_error=on_error, validate_default=validate_default, strict=strict, ref=ref, metadata=metadata, serialization=serialization, ) if default is not PydanticUndefined: s['default'] = default return s class NullableSchema(TypedDict, total=False): type: Required[Literal['nullable']] schema: Required[CoreSchema] strict: bool ref: str metadata: dict[str, Any] serialization: SerSchema def nullable_schema( schema: CoreSchema, *, strict: bool | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> NullableSchema: """ Returns a schema that matches a nullable value, e.g.: ```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 ``` Args: schema: The schema to wrap strict: Whether the underlying schema should be validated with strict mode ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='nullable', schema=schema, strict=strict, ref=ref, metadata=metadata, serialization=serialization ) class UnionSchema(TypedDict, total=False): type: Required[Literal['union']] choices: Required[list[Union[CoreSchema, tuple[CoreSchema, str]]]] # default true, whether to automatically collapse unions with one element to the inner validator auto_collapse: bool custom_error_type: str custom_error_message: str custom_error_context: dict[str, Union[str, int, float]] mode: Literal['smart', 'left_to_right'] # default: 'smart' strict: bool ref: str metadata: dict[str, Any] serialization: SerSchema def union_schema( choices: list[CoreSchema | tuple[CoreSchema, str]], *, auto_collapse: bool | None = None, custom_error_type: str | None = None, custom_error_message: str | None = None, custom_error_context: dict[str, str | int] | None = None, mode: Literal['smart', 'left_to_right'] | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> UnionSchema: """ Returns a schema that matches a union value, e.g.: ```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' assert v.validate_python(1) == 1 ``` Args: choices: The schemas to match. If a tuple, the second item is used as the label for the case. auto_collapse: whether to automatically collapse unions with one element to the inner validator, default true custom_error_type: The custom error type to use if the validation fails custom_error_message: The custom error message to use if the validation fails custom_error_context: The custom error context to use if the validation fails mode: How to select which choice to return * `smart` (default) will try to return the choice which is the closest match to the input value * `left_to_right` will return the first choice in `choices` which succeeds validation ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='union', choices=choices, auto_collapse=auto_collapse, custom_error_type=custom_error_type, custom_error_message=custom_error_message, custom_error_context=custom_error_context, mode=mode, ref=ref, metadata=metadata, serialization=serialization, ) class TaggedUnionSchema(TypedDict, total=False): type: Required[Literal['tagged-union']] choices: Required[dict[Hashable, CoreSchema]] discriminator: Required[Union[str, list[Union[str, int]], list[list[Union[str, int]]], Callable[[Any], Hashable]]] custom_error_type: str custom_error_message: str custom_error_context: dict[str, Union[str, int, float]] strict: bool from_attributes: bool # default: True ref: str metadata: dict[str, Any] serialization: SerSchema def tagged_union_schema( choices: dict[Any, CoreSchema], discriminator: str | list[str | int] | list[list[str | int]] | Callable[[Any], Any], *, custom_error_type: str | None = None, custom_error_message: str | None = None, custom_error_context: dict[str, int | str | float] | None = None, strict: bool | None = None, from_attributes: bool | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> TaggedUnionSchema: """ Returns a schema that matches a tagged union value, e.g.: ```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()), 'bar': core_schema.typed_dict_field(core_schema.int_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()) ), } ) schema = core_schema.tagged_union_schema( choices={ 'apple': apple_schema, 'banana': banana_schema, }, discriminator='foo', ) 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], } ``` Args: choices: The schemas to match When retrieving a schema from `choices` using the discriminator value, if the value is a str, it should be fed back into the `choices` map until a schema is obtained (This approach is to prevent multiple ownership of a single schema in Rust) discriminator: The discriminator to use to determine the schema to use * If `discriminator` is a str, it is the name of the attribute to use as the discriminator * If `discriminator` is a list of int/str, it should be used as a "path" to access the discriminator * If `discriminator` is a list of lists, each inner list is a path, and the first path that exists is used * If `discriminator` is a callable, it should return the discriminator when called on the value to validate; the callable can return `None` to indicate that there is no matching discriminator present on the input custom_error_type: The custom error type to use if the validation fails custom_error_message: The custom error message to use if the validation fails custom_error_context: The custom error context to use if the validation fails strict: Whether the underlying schemas should be validated with strict mode from_attributes: Whether to use the attributes of the object to retrieve the discriminator value ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='tagged-union', choices=choices, discriminator=discriminator, custom_error_type=custom_error_type, custom_error_message=custom_error_message, custom_error_context=custom_error_context, strict=strict, from_attributes=from_attributes, ref=ref, metadata=metadata, serialization=serialization, ) class ChainSchema(TypedDict, total=False): type: Required[Literal['chain']] steps: Required[list[CoreSchema]] ref: str metadata: dict[str, Any] serialization: SerSchema def chain_schema( steps: list[CoreSchema], *, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> ChainSchema: """ Returns a schema that chains the provided validation schemas, e.g.: ```py from pydantic_core import SchemaValidator, core_schema def fn(v: str, info: core_schema.ValidationInfo) -> str: assert 'hello' in v return v + ' world' fn_schema = core_schema.with_info_plain_validator_function(function=fn) 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' ``` Args: steps: The schemas to chain ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none(type='chain', steps=steps, ref=ref, metadata=metadata, serialization=serialization) class LaxOrStrictSchema(TypedDict, total=False): type: Required[Literal['lax-or-strict']] lax_schema: Required[CoreSchema] strict_schema: Required[CoreSchema] strict: bool ref: str metadata: dict[str, Any] serialization: SerSchema def lax_or_strict_schema( lax_schema: CoreSchema, strict_schema: CoreSchema, *, strict: bool | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> LaxOrStrictSchema: """ Returns a schema that uses the lax or strict schema, e.g.: ```py from pydantic_core import SchemaValidator, core_schema def fn(v: str, info: core_schema.ValidationInfo) -> str: assert 'hello' in v return v + ' world' 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 ) 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 ) v = SchemaValidator(schema) assert v.validate_python('123') == 123 ``` Args: lax_schema: The lax schema to use strict_schema: The strict schema to use strict: Whether the strict schema should be used ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='lax-or-strict', lax_schema=lax_schema, strict_schema=strict_schema, strict=strict, ref=ref, metadata=metadata, serialization=serialization, ) class JsonOrPythonSchema(TypedDict, total=False): type: Required[Literal['json-or-python']] json_schema: Required[CoreSchema] python_schema: Required[CoreSchema] ref: str metadata: dict[str, Any] serialization: SerSchema def json_or_python_schema( json_schema: CoreSchema, python_schema: CoreSchema, *, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> JsonOrPythonSchema: """ Returns a schema that uses the Json or Python schema depending on the input: ```py from pydantic_core import SchemaValidator, ValidationError, core_schema v = SchemaValidator( core_schema.json_or_python_schema( json_schema=core_schema.int_schema(), python_schema=core_schema.int_schema(strict=True), ) ) assert v.validate_json('"123"') == 123 try: v.validate_python('123') except ValidationError: pass else: raise AssertionError('Validation should have failed') ``` Args: json_schema: The schema to use for Json inputs python_schema: The schema to use for Python inputs ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='json-or-python', json_schema=json_schema, python_schema=python_schema, ref=ref, metadata=metadata, serialization=serialization, ) class TypedDictField(TypedDict, total=False): type: Required[Literal['typed-dict-field']] schema: Required[CoreSchema] required: bool validation_alias: Union[str, list[Union[str, int]], list[list[Union[str, int]]]] serialization_alias: str serialization_exclude: bool # default: False metadata: dict[str, Any] serialization_exclude_if: Callable[[Any], bool] # default None def typed_dict_field( schema: CoreSchema, *, required: bool | None = None, validation_alias: str | list[str | int] | list[list[str | int]] | None = None, serialization_alias: str | None = None, serialization_exclude: bool | None = None, metadata: dict[str, Any] | None = None, serialization_exclude_if: Callable[[Any], bool] | None = None, ) -> TypedDictField: """ Returns a schema that matches a typed dict field, e.g.: ```py from pydantic_core import core_schema field = core_schema.typed_dict_field(schema=core_schema.int_schema(), required=True) ``` Args: schema: The schema to use for the field required: Whether the field is required, otherwise uses the value from `total` on the typed dict validation_alias: The alias(es) to use to find the field in the validation data serialization_alias: The alias to use as a key when serializing serialization_exclude: Whether to exclude the field when serializing serialization_exclude_if: A callable that determines whether to exclude the field when serializing based on its value. metadata: Any other information you want to include with the schema, not used by pydantic-core """ return _dict_not_none( type='typed-dict-field', schema=schema, required=required, validation_alias=validation_alias, serialization_alias=serialization_alias, serialization_exclude=serialization_exclude, serialization_exclude_if=serialization_exclude_if, metadata=metadata, ) class TypedDictSchema(TypedDict, total=False): type: Required[Literal['typed-dict']] fields: Required[dict[str, TypedDictField]] cls: type[Any] cls_name: str computed_fields: list[ComputedField] strict: bool extras_schema: CoreSchema # all these values can be set via config, equivalent fields have `typed_dict_` prefix extra_behavior: ExtraBehavior total: bool # default: True ref: str metadata: dict[str, Any] serialization: SerSchema config: CoreConfig def typed_dict_schema( fields: dict[str, TypedDictField], *, cls: type[Any] | None = None, cls_name: str | None = None, computed_fields: list[ComputedField] | None = None, strict: bool | None = None, extras_schema: CoreSchema | None = None, extra_behavior: ExtraBehavior | None = None, total: bool | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, config: CoreConfig | None = None, ) -> TypedDictSchema: """ Returns a schema that matches a typed dict, e.g.: ```py from typing_extensions import TypedDict from pydantic_core import SchemaValidator, core_schema class MyTypedDict(TypedDict): a: str wrapper_schema = core_schema.typed_dict_schema( {'a': core_schema.typed_dict_field(core_schema.str_schema())}, cls=MyTypedDict ) v = SchemaValidator(wrapper_schema) assert v.validate_python({'a': 'hello'}) == {'a': 'hello'} ``` Args: fields: The fields to use for the typed dict cls: The class to use for the typed dict cls_name: The name to use in error locations. Falls back to `cls.__name__`, or the validator name if no class is provided. computed_fields: Computed fields to use when serializing the model, only applies when directly inside a model strict: Whether the typed dict is strict extras_schema: The extra validator to use for the typed dict ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core extra_behavior: The extra behavior to use for the typed dict total: Whether the typed dict is total, otherwise uses `typed_dict_total` from config serialization: Custom serialization schema """ return _dict_not_none( type='typed-dict', fields=fields, cls=cls, cls_name=cls_name, computed_fields=computed_fields, strict=strict, extras_schema=extras_schema, extra_behavior=extra_behavior, total=total, ref=ref, metadata=metadata, serialization=serialization, config=config, ) class ModelField(TypedDict, total=False): type: Required[Literal['model-field']] schema: Required[CoreSchema] validation_alias: Union[str, list[Union[str, int]], list[list[Union[str, int]]]] serialization_alias: str serialization_exclude: bool # default: False serialization_exclude_if: Callable[[Any], bool] # default: None frozen: bool metadata: dict[str, Any] def model_field( schema: CoreSchema, *, validation_alias: str | list[str | int] | list[list[str | int]] | None = None, serialization_alias: str | None = None, serialization_exclude: bool | None = None, serialization_exclude_if: Callable[[Any], bool] | None = None, frozen: bool | None = None, metadata: dict[str, Any] | None = None, ) -> ModelField: """ Returns a schema for a model field, e.g.: ```py from pydantic_core import core_schema field = core_schema.model_field(schema=core_schema.int_schema()) ``` Args: schema: The schema to use for the field validation_alias: The alias(es) to use to find the field in the validation data serialization_alias: The alias to use as a key when serializing serialization_exclude: Whether to exclude the field when serializing serialization_exclude_if: A Callable that determines whether to exclude a field during serialization based on its value. frozen: Whether the field is frozen metadata: Any other information you want to include with the schema, not used by pydantic-core """ return _dict_not_none( type='model-field', schema=schema, validation_alias=validation_alias, serialization_alias=serialization_alias, serialization_exclude=serialization_exclude, serialization_exclude_if=serialization_exclude_if, frozen=frozen, metadata=metadata, ) class ModelFieldsSchema(TypedDict, total=False): type: Required[Literal['model-fields']] fields: Required[dict[str, ModelField]] model_name: str computed_fields: list[ComputedField] strict: bool extras_schema: CoreSchema extras_keys_schema: CoreSchema extra_behavior: ExtraBehavior from_attributes: bool ref: str metadata: dict[str, Any] serialization: SerSchema def model_fields_schema( fields: dict[str, ModelField], *, model_name: str | None = None, computed_fields: list[ComputedField] | None = None, strict: bool | None = None, extras_schema: CoreSchema | None = None, extras_keys_schema: CoreSchema | None = None, extra_behavior: ExtraBehavior | None = None, from_attributes: bool | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> ModelFieldsSchema: """ Returns a schema that matches the fields of a Pydantic model, e.g.: ```py from pydantic_core import SchemaValidator, core_schema wrapper_schema = core_schema.model_fields_schema( {'a': core_schema.model_field(core_schema.str_schema())} ) v = SchemaValidator(wrapper_schema) print(v.validate_python({'a': 'hello'})) #> ({'a': 'hello'}, None, {'a'}) ``` Args: fields: The fields of the model model_name: The name of the model, used for error messages, defaults to "Model" computed_fields: Computed fields to use when serializing the model, only applies when directly inside a model strict: Whether the model is strict extras_schema: The schema to use when validating extra input data extras_keys_schema: The schema to use when validating the keys of extra input data ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core extra_behavior: The extra behavior to use for the model fields from_attributes: Whether the model fields should be populated from attributes serialization: Custom serialization schema """ return _dict_not_none( type='model-fields', fields=fields, model_name=model_name, computed_fields=computed_fields, strict=strict, extras_schema=extras_schema, extras_keys_schema=extras_keys_schema, extra_behavior=extra_behavior, from_attributes=from_attributes, ref=ref, metadata=metadata, serialization=serialization, ) class ModelSchema(TypedDict, total=False): type: Required[Literal['model']] cls: Required[type[Any]] generic_origin: type[Any] schema: Required[CoreSchema] custom_init: bool root_model: bool post_init: str revalidate_instances: Literal['always', 'never', 'subclass-instances'] # default: 'never' strict: bool frozen: bool extra_behavior: ExtraBehavior config: CoreConfig ref: str metadata: dict[str, Any] serialization: SerSchema def model_schema( cls: type[Any], schema: CoreSchema, *, generic_origin: type[Any] | None = None, custom_init: bool | None = None, root_model: bool | None = None, post_init: str | None = None, revalidate_instances: Literal['always', 'never', 'subclass-instances'] | None = None, strict: bool | None = None, frozen: bool | None = None, extra_behavior: ExtraBehavior | None = None, config: CoreConfig | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> ModelSchema: """ A model schema generally contains a typed-dict schema. It will run the typed dict validator, then create a new class and set the dict and fields set returned from the typed dict validator to `__dict__` and `__pydantic_fields_set__` respectively. Example: ```py from pydantic_core import CoreConfig, SchemaValidator, core_schema class MyModel: __slots__ = ( '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__', ) schema = core_schema.model_schema( cls=MyModel, config=CoreConfig(str_max_length=5), schema=core_schema.model_fields_schema( fields={'a': core_schema.model_field(core_schema.str_schema())}, ), ) v = SchemaValidator(schema) assert v.isinstance_python({'a': 'hello'}) is True assert v.isinstance_python({'a': 'too long'}) is False ``` Args: cls: The class to use for the model schema: The schema to use for the model generic_origin: The origin type used for this model, if it's a parametrized generic. Ex, if this model schema represents `SomeModel[int]`, generic_origin is `SomeModel` custom_init: Whether the model has a custom init method root_model: Whether the model is a `RootModel` post_init: The call after init to use for the model revalidate_instances: whether instances of models and dataclasses (including subclass instances) should re-validate defaults to config.revalidate_instances, else 'never' strict: Whether the model is strict frozen: Whether the model is frozen extra_behavior: The extra behavior to use for the model, used in serialization config: The config to use for the model ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='model', cls=cls, generic_origin=generic_origin, schema=schema, custom_init=custom_init, root_model=root_model, post_init=post_init, revalidate_instances=revalidate_instances, strict=strict, frozen=frozen, extra_behavior=extra_behavior, config=config, ref=ref, metadata=metadata, serialization=serialization, ) class DataclassField(TypedDict, total=False): type: Required[Literal['dataclass-field']] name: Required[str] schema: Required[CoreSchema] kw_only: bool # default: True init: bool # default: True init_only: bool # default: False frozen: bool # default: False validation_alias: Union[str, list[Union[str, int]], list[list[Union[str, int]]]] serialization_alias: str serialization_exclude: bool # default: False metadata: dict[str, Any] serialization_exclude_if: Callable[[Any], bool] # default: None def dataclass_field( name: str, schema: CoreSchema, *, kw_only: bool | None = None, init: bool | None = None, init_only: bool | None = None, validation_alias: str | list[str | int] | list[list[str | int]] | None = None, serialization_alias: str | None = None, serialization_exclude: bool | None = None, metadata: dict[str, Any] | None = None, serialization_exclude_if: Callable[[Any], bool] | None = None, frozen: bool | None = None, ) -> DataclassField: """ Returns a schema for a dataclass field, e.g.: ```py from pydantic_core import SchemaValidator, core_schema 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) ``` Args: name: The name to use for the argument parameter schema: The schema to use for the argument parameter kw_only: Whether the field can be set with a positional argument as well as a keyword argument init: Whether the field should be validated during initialization init_only: Whether the field should be omitted from `__dict__` and passed to `__post_init__` validation_alias: The alias(es) to use to find the field in the validation data serialization_alias: The alias to use as a key when serializing serialization_exclude: Whether to exclude the field when serializing serialization_exclude_if: A callable that determines whether to exclude the field when serializing based on its value. metadata: Any other information you want to include with the schema, not used by pydantic-core frozen: Whether the field is frozen """ return _dict_not_none( type='dataclass-field', name=name, schema=schema, kw_only=kw_only, init=init, init_only=init_only, validation_alias=validation_alias, serialization_alias=serialization_alias, serialization_exclude=serialization_exclude, serialization_exclude_if=serialization_exclude_if, metadata=metadata, frozen=frozen, ) class DataclassArgsSchema(TypedDict, total=False): type: Required[Literal['dataclass-args']] dataclass_name: Required[str] fields: Required[list[DataclassField]] computed_fields: list[ComputedField] collect_init_only: bool # default: False ref: str metadata: dict[str, Any] serialization: SerSchema extra_behavior: ExtraBehavior def dataclass_args_schema( dataclass_name: str, fields: list[DataclassField], *, computed_fields: list[ComputedField] | None = None, collect_init_only: bool | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, extra_behavior: ExtraBehavior | None = None, ) -> DataclassArgsSchema: """ Returns a schema for validating dataclass arguments, e.g.: ```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 ) 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) ``` Args: dataclass_name: The name of the dataclass being validated fields: The fields to use for the dataclass computed_fields: Computed fields to use when serializing the dataclass collect_init_only: Whether to collect init only fields into a dict to pass to `__post_init__` ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema extra_behavior: How to handle extra fields """ return _dict_not_none( type='dataclass-args', dataclass_name=dataclass_name, fields=fields, computed_fields=computed_fields, collect_init_only=collect_init_only, ref=ref, metadata=metadata, serialization=serialization, extra_behavior=extra_behavior, ) class DataclassSchema(TypedDict, total=False): type: Required[Literal['dataclass']] cls: Required[type[Any]] generic_origin: type[Any] schema: Required[CoreSchema] fields: Required[list[str]] cls_name: str post_init: bool # default: False revalidate_instances: Literal['always', 'never', 'subclass-instances'] # default: 'never' strict: bool # default: False frozen: bool # default False ref: str metadata: dict[str, Any] serialization: SerSchema slots: bool config: CoreConfig def dataclass_schema( cls: type[Any], schema: CoreSchema, fields: list[str], *, generic_origin: type[Any] | None = None, cls_name: str | None = None, post_init: bool | None = None, revalidate_instances: Literal['always', 'never', 'subclass-instances'] | None = None, strict: bool | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, frozen: bool | None = None, slots: bool | None = None, config: CoreConfig | None = None, ) -> DataclassSchema: """ Returns a schema for a dataclass. As with `ModelSchema`, this schema can only be used as a field within another schema, not as the root type. Args: cls: The dataclass type, used to perform subclass checks schema: The schema to use for the dataclass fields fields: Fields of the dataclass, this is used in serialization and in validation during re-validation and while validating assignment generic_origin: The origin type used for this dataclass, if it's a parametrized generic. Ex, if this model schema represents `SomeDataclass[int]`, generic_origin is `SomeDataclass` cls_name: The name to use in error locs, etc; this is useful for generics (default: `cls.__name__`) post_init: Whether to call `__post_init__` after validation revalidate_instances: whether instances of models and dataclasses (including subclass instances) should re-validate defaults to config.revalidate_instances, else 'never' strict: Whether to require an exact instance of `cls` ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema frozen: Whether the dataclass is frozen slots: Whether `slots=True` on the dataclass, means each field is assigned independently, rather than simply setting `__dict__`, default false """ return _dict_not_none( type='dataclass', cls=cls, generic_origin=generic_origin, fields=fields, cls_name=cls_name, schema=schema, post_init=post_init, revalidate_instances=revalidate_instances, strict=strict, ref=ref, metadata=metadata, serialization=serialization, frozen=frozen, slots=slots, config=config, ) class ArgumentsParameter(TypedDict, total=False): name: Required[str] schema: Required[CoreSchema] mode: Literal['positional_only', 'positional_or_keyword', 'keyword_only'] # default positional_or_keyword alias: Union[str, list[Union[str, int]], list[list[Union[str, int]]]] def arguments_parameter( name: str, schema: CoreSchema, *, mode: Literal['positional_only', 'positional_or_keyword', 'keyword_only'] | None = None, alias: str | list[str | int] | list[list[str | int]] | None = None, ) -> ArgumentsParameter: """ Returns a schema that matches an argument parameter, e.g.: ```py from pydantic_core import SchemaValidator, core_schema 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',), {}) ``` Args: name: The name to use for the argument parameter schema: The schema to use for the argument parameter mode: The mode to use for the argument parameter alias: The alias to use for the argument parameter """ return _dict_not_none(name=name, schema=schema, mode=mode, alias=alias) VarKwargsMode: TypeAlias = Literal['uniform', 'unpacked-typed-dict'] class ArgumentsSchema(TypedDict, total=False): type: Required[Literal['arguments']] arguments_schema: Required[list[ArgumentsParameter]] validate_by_name: bool validate_by_alias: bool var_args_schema: CoreSchema var_kwargs_mode: VarKwargsMode var_kwargs_schema: CoreSchema ref: str metadata: dict[str, Any] serialization: SerSchema def arguments_schema( arguments: list[ArgumentsParameter], *, validate_by_name: bool | None = None, validate_by_alias: bool | None = None, var_args_schema: CoreSchema | None = None, var_kwargs_mode: VarKwargsMode | None = None, var_kwargs_schema: CoreSchema | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> ArgumentsSchema: """ Returns a schema that matches an arguments schema, e.g.: ```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' ) schema = core_schema.arguments_schema([param_a, param_b]) v = SchemaValidator(schema) assert v.validate_python(('hello', True)) == (('hello', True), {}) ``` Args: arguments: The arguments to use for the arguments schema validate_by_name: Whether to populate by the parameter names, defaults to `False`. validate_by_alias: Whether to populate by the parameter aliases, defaults to `True`. var_args_schema: The variable args schema to use for the arguments schema var_kwargs_mode: The validation mode to use for variadic keyword arguments. If `'uniform'`, every value of the keyword arguments will be validated against the `var_kwargs_schema` schema. If `'unpacked-typed-dict'`, the `var_kwargs_schema` argument must be a [`typed_dict_schema`][pydantic_core.core_schema.typed_dict_schema] var_kwargs_schema: The variable kwargs schema to use for the arguments schema ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='arguments', arguments_schema=arguments, validate_by_name=validate_by_name, validate_by_alias=validate_by_alias, var_args_schema=var_args_schema, var_kwargs_mode=var_kwargs_mode, var_kwargs_schema=var_kwargs_schema, ref=ref, metadata=metadata, serialization=serialization, ) class ArgumentsV3Parameter(TypedDict, total=False): name: Required[str] schema: Required[CoreSchema] mode: Literal[ 'positional_only', 'positional_or_keyword', 'keyword_only', 'var_args', 'var_kwargs_uniform', 'var_kwargs_unpacked_typed_dict', ] # default positional_or_keyword alias: Union[str, list[Union[str, int]], list[list[Union[str, int]]]] def arguments_v3_parameter( name: str, schema: CoreSchema, *, mode: Literal[ 'positional_only', 'positional_or_keyword', 'keyword_only', 'var_args', 'var_kwargs_uniform', 'var_kwargs_unpacked_typed_dict', ] | None = None, alias: str | list[str | int] | list[list[str | int]] | None = None, ) -> ArgumentsV3Parameter: """ Returns a schema that matches an argument parameter, e.g.: ```py from pydantic_core import SchemaValidator, core_schema param = core_schema.arguments_v3_parameter( name='a', schema=core_schema.str_schema(), mode='positional_only' ) schema = core_schema.arguments_v3_schema([param]) v = SchemaValidator(schema) assert v.validate_python({'a': 'hello'}) == (('hello',), {}) ``` Args: name: The name to use for the argument parameter schema: The schema to use for the argument parameter mode: The mode to use for the argument parameter alias: The alias to use for the argument parameter """ return _dict_not_none(name=name, schema=schema, mode=mode, alias=alias) class ArgumentsV3Schema(TypedDict, total=False): type: Required[Literal['arguments-v3']] arguments_schema: Required[list[ArgumentsV3Parameter]] validate_by_name: bool validate_by_alias: bool extra_behavior: Literal['forbid', 'ignore'] # 'allow' doesn't make sense here. ref: str metadata: dict[str, Any] serialization: SerSchema def arguments_v3_schema( arguments: list[ArgumentsV3Parameter], *, validate_by_name: bool | None = None, validate_by_alias: bool | None = None, extra_behavior: Literal['forbid', 'ignore'] | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> ArgumentsV3Schema: """ Returns a schema that matches an arguments schema, e.g.: ```py from pydantic_core import SchemaValidator, core_schema param_a = core_schema.arguments_v3_parameter( name='a', schema=core_schema.str_schema(), mode='positional_only' ) param_b = core_schema.arguments_v3_parameter( name='kwargs', schema=core_schema.bool_schema(), mode='var_kwargs_uniform' ) schema = core_schema.arguments_v3_schema([param_a, param_b]) v = SchemaValidator(schema) assert v.validate_python({'a': 'hi', 'kwargs': {'b': True}}) == (('hi',), {'b': True}) ``` This schema is currently not used by other Pydantic components. In V3, it will most likely become the default arguments schema for the `'call'` schema. Args: arguments: The arguments to use for the arguments schema. validate_by_name: Whether to populate by the parameter names, defaults to `False`. validate_by_alias: Whether to populate by the parameter aliases, defaults to `True`. extra_behavior: The extra behavior to use. ref: optional unique identifier of the schema, used to reference the schema in other places. metadata: Any other information you want to include with the schema, not used by pydantic-core. serialization: Custom serialization schema. """ return _dict_not_none( type='arguments-v3', arguments_schema=arguments, validate_by_name=validate_by_name, validate_by_alias=validate_by_alias, extra_behavior=extra_behavior, ref=ref, metadata=metadata, serialization=serialization, ) class CallSchema(TypedDict, total=False): type: Required[Literal['call']] arguments_schema: Required[CoreSchema] function: Required[Callable[..., Any]] function_name: str # default function.__name__ return_schema: CoreSchema ref: str metadata: dict[str, Any] serialization: SerSchema def call_schema( arguments: CoreSchema, function: Callable[..., Any], *, function_name: str | None = None, return_schema: CoreSchema | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> CallSchema: """ Returns a schema that matches an arguments schema, then calls a function, e.g.: ```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' ) args_schema = core_schema.arguments_schema([param_a, param_b]) schema = core_schema.call_schema( arguments=args_schema, function=lambda a, b: a + str(not b), return_schema=core_schema.str_schema(), ) v = SchemaValidator(schema) assert v.validate_python((('hello', True))) == 'helloFalse' ``` Args: arguments: The arguments to use for the arguments schema function: The function to use for the call schema function_name: The function name to use for the call schema, if not provided `function.__name__` is used return_schema: The return schema to use for the call schema ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='call', arguments_schema=arguments, function=function, function_name=function_name, return_schema=return_schema, ref=ref, metadata=metadata, serialization=serialization, ) class CustomErrorSchema(TypedDict, total=False): type: Required[Literal['custom-error']] schema: Required[CoreSchema] custom_error_type: Required[str] custom_error_message: str custom_error_context: dict[str, Union[str, int, float]] ref: str metadata: dict[str, Any] serialization: SerSchema def custom_error_schema( schema: CoreSchema, custom_error_type: str, *, custom_error_message: str | None = None, custom_error_context: dict[str, Any] | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> CustomErrorSchema: """ Returns a schema that matches a custom error value, e.g.: ```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', ) v = SchemaValidator(schema) v.validate_python(1) ``` Args: schema: The schema to use for the custom error schema custom_error_type: The custom error type to use for the custom error schema custom_error_message: The custom error message to use for the custom error schema custom_error_context: The custom error context to use for the custom error schema ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='custom-error', schema=schema, custom_error_type=custom_error_type, custom_error_message=custom_error_message, custom_error_context=custom_error_context, ref=ref, metadata=metadata, serialization=serialization, ) class JsonSchema(TypedDict, total=False): type: Required[Literal['json']] schema: CoreSchema ref: str metadata: dict[str, Any] serialization: SerSchema def json_schema( schema: CoreSchema | None = None, *, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> JsonSchema: """ Returns a schema that matches a JSON value, e.g.: ```py from pydantic_core import SchemaValidator, core_schema dict_schema = core_schema.model_fields_schema( { 'field_a': core_schema.model_field(core_schema.str_schema()), 'field_b': core_schema.model_field(core_schema.bool_schema()), }, ) class MyModel: __slots__ = ( '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__', ) field_a: str field_b: bool json_schema = core_schema.json_schema(schema=dict_schema) schema = core_schema.model_schema(cls=MyModel, schema=json_schema) v = SchemaValidator(schema) m = v.validate_python('{"field_a": "hello", "field_b": true}') assert isinstance(m, MyModel) ``` Args: schema: The schema to use for the JSON schema ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none(type='json', schema=schema, ref=ref, metadata=metadata, serialization=serialization) class UrlSchema(TypedDict, total=False): type: Required[Literal['url']] max_length: int allowed_schemes: list[str] host_required: bool # default False default_host: str default_port: int default_path: str strict: bool ref: str metadata: dict[str, Any] serialization: SerSchema def url_schema( *, max_length: int | None = None, allowed_schemes: list[str] | None = None, host_required: bool | None = None, default_host: str | None = None, default_port: int | None = None, default_path: str | None = None, preserve_empty_path: bool | None = None, strict: bool | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> UrlSchema: """ Returns a schema that matches a URL value, e.g.: ```py from pydantic_core import SchemaValidator, core_schema schema = core_schema.url_schema() v = SchemaValidator(schema) print(v.validate_python('https://example.com')) #> https://example.com/ ``` Args: max_length: The maximum length of the URL allowed_schemes: The allowed URL schemes host_required: Whether the URL must have a host default_host: The default host to use if the URL does not have a host default_port: The default port to use if the URL does not have a port default_path: The default path to use if the URL does not have a path preserve_empty_path: Whether to preserve an empty path or convert it to '/', default False strict: Whether to use strict URL parsing ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='url', max_length=max_length, allowed_schemes=allowed_schemes, host_required=host_required, default_host=default_host, default_port=default_port, default_path=default_path, preserve_empty_path=preserve_empty_path, strict=strict, ref=ref, metadata=metadata, serialization=serialization, ) class MultiHostUrlSchema(TypedDict, total=False): type: Required[Literal['multi-host-url']] max_length: int allowed_schemes: list[str] host_required: bool # default False default_host: str default_port: int default_path: str strict: bool ref: str metadata: dict[str, Any] serialization: SerSchema def multi_host_url_schema( *, max_length: int | None = None, allowed_schemes: list[str] | None = None, host_required: bool | None = None, default_host: str | None = None, default_port: int | None = None, default_path: str | None = None, preserve_empty_path: bool | None = None, strict: bool | None = None, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> MultiHostUrlSchema: """ Returns a schema that matches a URL value with possibly multiple hosts, e.g.: ```py from pydantic_core import SchemaValidator, core_schema schema = core_schema.multi_host_url_schema() v = SchemaValidator(schema) print(v.validate_python('redis://localhost,0.0.0.0,127.0.0.1')) #> redis://localhost,0.0.0.0,127.0.0.1 ``` Args: max_length: The maximum length of the URL allowed_schemes: The allowed URL schemes host_required: Whether the URL must have a host default_host: The default host to use if the URL does not have a host default_port: The default port to use if the URL does not have a port default_path: The default path to use if the URL does not have a path preserve_empty_path: Whether to preserve an empty path or convert it to '/', default False strict: Whether to use strict URL parsing ref: optional unique identifier of the schema, used to reference the schema in other places metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='multi-host-url', max_length=max_length, allowed_schemes=allowed_schemes, host_required=host_required, default_host=default_host, default_port=default_port, default_path=default_path, preserve_empty_path=preserve_empty_path, strict=strict, ref=ref, metadata=metadata, serialization=serialization, ) class DefinitionsSchema(TypedDict, total=False): type: Required[Literal['definitions']] schema: Required[CoreSchema] definitions: Required[list[CoreSchema]] metadata: dict[str, Any] serialization: SerSchema def definitions_schema(schema: CoreSchema, definitions: list[CoreSchema]) -> DefinitionsSchema: """ Build a schema that contains both an inner schema and a list of definitions which can be used within the inner schema. ```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')], ) v = SchemaValidator(schema) assert v.validate_python([1, 2, '3']) == [1, 2, 3] ``` Args: schema: The inner schema definitions: List of definitions which can be referenced within inner schema """ return DefinitionsSchema(type='definitions', schema=schema, definitions=definitions) class DefinitionReferenceSchema(TypedDict, total=False): type: Required[Literal['definition-ref']] schema_ref: Required[str] ref: str metadata: dict[str, Any] serialization: SerSchema def definition_reference_schema( schema_ref: str, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None, ) -> DefinitionReferenceSchema: """ Returns a schema that points to a schema stored in "definitions", this is useful for nested recursive models and also when you want to define validators separately from the main schema, e.g.: ```py from pydantic_core import SchemaValidator, core_schema schema_definition = core_schema.definition_reference_schema('list-schema') schema = core_schema.definitions_schema( schema=schema_definition, definitions=[ core_schema.list_schema(items_schema=schema_definition, ref='list-schema'), ], ) v = SchemaValidator(schema) assert v.validate_python([()]) == [[]] ``` Args: schema_ref: The schema ref to use for the definition reference schema metadata: Any other information you want to include with the schema, not used by pydantic-core serialization: Custom serialization schema """ return _dict_not_none( type='definition-ref', schema_ref=schema_ref, ref=ref, metadata=metadata, serialization=serialization ) MYPY = False # See https://github.com/python/mypy/issues/14034 for details, in summary mypy is extremely slow to process this # union which kills performance not just for pydantic, but even for code using pydantic if not MYPY: CoreSchema = Union[ InvalidSchema, AnySchema, NoneSchema, BoolSchema, IntSchema, FloatSchema, DecimalSchema, StringSchema, BytesSchema, DateSchema, TimeSchema, DatetimeSchema, TimedeltaSchema, LiteralSchema, MissingSentinelSchema, EnumSchema, IsInstanceSchema, IsSubclassSchema, CallableSchema, ListSchema, TupleSchema, SetSchema, FrozenSetSchema, GeneratorSchema, DictSchema, AfterValidatorFunctionSchema, BeforeValidatorFunctionSchema, WrapValidatorFunctionSchema, PlainValidatorFunctionSchema, WithDefaultSchema, NullableSchema, UnionSchema, TaggedUnionSchema, ChainSchema, LaxOrStrictSchema, JsonOrPythonSchema, TypedDictSchema, ModelFieldsSchema, ModelSchema, DataclassArgsSchema, DataclassSchema, ArgumentsSchema, ArgumentsV3Schema, CallSchema, CustomErrorSchema, JsonSchema, UrlSchema, MultiHostUrlSchema, DefinitionsSchema, DefinitionReferenceSchema, UuidSchema, ComplexSchema, ] elif False: CoreSchema: TypeAlias = Mapping[str, Any] # to update this, call `pytest -k test_core_schema_type_literal` and copy the output CoreSchemaType = Literal[ 'invalid', 'any', 'none', 'bool', 'int', 'float', 'decimal', 'str', 'bytes', 'date', 'time', 'datetime', 'timedelta', 'literal', 'missing-sentinel', 'enum', 'is-instance', 'is-subclass', 'callable', 'list', 'tuple', 'set', 'frozenset', 'generator', 'dict', 'function-after', 'function-before', 'function-wrap', 'function-plain', 'default', 'nullable', 'union', 'tagged-union', 'chain', 'lax-or-strict', 'json-or-python', 'typed-dict', 'model-fields', 'model', 'dataclass-args', 'dataclass', 'arguments', 'arguments-v3', 'call', 'custom-error', 'json', 'url', 'multi-host-url', 'definitions', 'definition-ref', 'uuid', 'complex', ] CoreSchemaFieldType = Literal['model-field', 'dataclass-field', 'typed-dict-field', 'computed-field'] # used in _pydantic_core.pyi::PydanticKnownError # to update this, call `pytest -k test_all_errors` and copy the output ErrorType = Literal[ 'no_such_attribute', 'json_invalid', 'json_type', 'needs_python_object', 'recursion_loop', 'missing', 'frozen_field', 'frozen_instance', 'extra_forbidden', 'invalid_key', 'get_attribute_error', 'model_type', 'model_attributes_type', 'dataclass_type', 'dataclass_exact_type', 'default_factory_not_called', 'none_required', 'greater_than', 'greater_than_equal', 'less_than', 'less_than_equal', 'multiple_of', 'finite_number', 'too_short', 'too_long', 'iterable_type', 'iteration_error', 'string_type', 'string_sub_type', 'string_unicode', 'string_too_short', 'string_too_long', 'string_pattern_mismatch', 'string_not_ascii', 'enum', 'dict_type', 'mapping_type', 'list_type', 'tuple_type', 'set_type', 'set_item_not_hashable', 'bool_type', 'bool_parsing', 'int_type', 'int_parsing', 'int_parsing_size', 'int_from_float', 'float_type', 'float_parsing', 'bytes_type', 'bytes_too_short', 'bytes_too_long', 'bytes_invalid_encoding', 'value_error', 'assertion_error', 'literal_error', 'missing_sentinel_error', 'date_type', 'date_parsing', 'date_from_datetime_parsing', 'date_from_datetime_inexact', 'date_past', 'date_future', 'time_type', 'time_parsing', 'datetime_type', 'datetime_parsing', 'datetime_object_invalid', 'datetime_from_date_parsing', 'datetime_past', 'datetime_future', 'timezone_naive', 'timezone_aware', 'timezone_offset', 'time_delta_type', 'time_delta_parsing', 'frozen_set_type', 'is_instance_of', 'is_subclass_of', 'callable_type', 'union_tag_invalid', 'union_tag_not_found', 'arguments_type', 'missing_argument', 'unexpected_keyword_argument', 'missing_keyword_only_argument', 'unexpected_positional_argument', 'missing_positional_only_argument', 'multiple_argument_values', 'url_type', 'url_parsing', 'url_syntax_violation', 'url_too_long', 'url_scheme', 'uuid_type', 'uuid_parsing', 'uuid_version', 'decimal_type', 'decimal_parsing', 'decimal_max_digits', 'decimal_max_places', 'decimal_whole_digits', 'complex_type', 'complex_str_parsing', ] def _dict_not_none(**kwargs: Any) -> Any: return {k: v for k, v in kwargs.items() if v is not None} def iter_union_choices(union_schema: UnionSchema) -> Generator[CoreSchema]: """Iterate over the choices of a `'union'` schema.""" for choice in union_schema['choices']: if isinstance(choice, tuple): yield choice[0] else: yield choice ############################################################################### # All this stuff is deprecated by #980 and will be removed eventually # They're kept because some code external code will be using them @deprecated('`field_before_validator_function` is deprecated, use `with_info_before_validator_function` instead.') def field_before_validator_function(function: WithInfoValidatorFunction, field_name: str, schema: CoreSchema, **kwargs): warnings.warn( '`field_before_validator_function` is deprecated, use `with_info_before_validator_function` instead.', DeprecationWarning, ) return with_info_before_validator_function(function, schema, field_name=field_name, **kwargs) @deprecated('`general_before_validator_function` is deprecated, use `with_info_before_validator_function` instead.') def general_before_validator_function(*args, **kwargs): warnings.warn( '`general_before_validator_function` is deprecated, use `with_info_before_validator_function` instead.', DeprecationWarning, ) return with_info_before_validator_function(*args, **kwargs) @deprecated('`field_after_validator_function` is deprecated, use `with_info_after_validator_function` instead.') def field_after_validator_function(function: WithInfoValidatorFunction, field_name: str, schema: CoreSchema, **kwargs): warnings.warn( '`field_after_validator_function` is deprecated, use `with_info_after_validator_function` instead.', DeprecationWarning, ) return with_info_after_validator_function(function, schema, field_name=field_name, **kwargs) @deprecated('`general_after_validator_function` is deprecated, use `with_info_after_validator_function` instead.') def general_after_validator_function(*args, **kwargs): warnings.warn( '`general_after_validator_function` is deprecated, use `with_info_after_validator_function` instead.', DeprecationWarning, ) return with_info_after_validator_function(*args, **kwargs) @deprecated('`field_wrap_validator_function` is deprecated, use `with_info_wrap_validator_function` instead.') def field_wrap_validator_function( function: WithInfoWrapValidatorFunction, field_name: str, schema: CoreSchema, **kwargs ): warnings.warn( '`field_wrap_validator_function` is deprecated, use `with_info_wrap_validator_function` instead.', DeprecationWarning, ) return with_info_wrap_validator_function(function, schema, field_name=field_name, **kwargs) @deprecated('`general_wrap_validator_function` is deprecated, use `with_info_wrap_validator_function` instead.') def general_wrap_validator_function(*args, **kwargs): warnings.warn( '`general_wrap_validator_function` is deprecated, use `with_info_wrap_validator_function` instead.', DeprecationWarning, ) return with_info_wrap_validator_function(*args, **kwargs) @deprecated('`field_plain_validator_function` is deprecated, use `with_info_plain_validator_function` instead.') def field_plain_validator_function(function: WithInfoValidatorFunction, field_name: str, **kwargs): warnings.warn( '`field_plain_validator_function` is deprecated, use `with_info_plain_validator_function` instead.', DeprecationWarning, ) return with_info_plain_validator_function(function, field_name=field_name, **kwargs) @deprecated('`general_plain_validator_function` is deprecated, use `with_info_plain_validator_function` instead.') def general_plain_validator_function(*args, **kwargs): warnings.warn( '`general_plain_validator_function` is deprecated, use `with_info_plain_validator_function` instead.', DeprecationWarning, ) return with_info_plain_validator_function(*args, **kwargs) _deprecated_import_lookup = { 'FieldValidationInfo': ValidationInfo, 'FieldValidatorFunction': WithInfoValidatorFunction, 'GeneralValidatorFunction': WithInfoValidatorFunction, 'FieldWrapValidatorFunction': WithInfoWrapValidatorFunction, } if TYPE_CHECKING: FieldValidationInfo = ValidationInfo def __getattr__(attr_name: str) -> object: new_attr = _deprecated_import_lookup.get(attr_name) if new_attr is None: raise AttributeError(f"module 'pydantic_core' has no attribute '{attr_name}'") else: import warnings msg = f'`{attr_name}` is deprecated, use `{new_attr.__name__}` instead.' warnings.warn(msg, DeprecationWarning, stacklevel=1) return new_attr pydantic-pydantic-ba0aa01/pydantic-core/python/pydantic_core/py.typed000066400000000000000000000000001517143232300262000ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/pydantic-core/src/000077500000000000000000000000001517143232300211365ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/pydantic-core/src/argument_markers.rs000066400000000000000000000045321517143232300250560ustar00rootroot00000000000000use pyo3::exceptions::PyNotImplementedError; use pyo3::prelude::*; use pyo3::sync::PyOnceLock; use pyo3::types::{PyDict, PyTuple}; use crate::tools::safe_repr; #[pyclass( module = "pydantic_core._pydantic_core", get_all, frozen, freelist = 100, skip_from_py_object )] #[derive(Debug, Clone)] pub struct ArgsKwargs { pub(crate) args: Py, pub(crate) kwargs: Option>, } #[pymethods] impl ArgsKwargs { #[new] #[pyo3(signature = (args, kwargs = None))] fn py_new(args: Bound<'_, PyTuple>, kwargs: Option>) -> Self { Self { args: args.unbind(), kwargs: kwargs.filter(|d| !d.is_empty()).map(Bound::unbind), } } fn __eq__(&self, py: Python, other: &Self) -> PyResult { if !self.args.bind(py).eq(&other.args)? { return Ok(false); } match (&self.kwargs, &other.kwargs) { (Some(d1), Some(d2)) => d1.bind(py).eq(d2), (None, None) => Ok(true), _ => Ok(false), } } pub fn __repr__(&self, py: Python) -> String { let args = safe_repr(self.args.bind(py)); match self.kwargs { Some(ref d) => format!("ArgsKwargs({args}, {})", safe_repr(d.bind(py))), None => format!("ArgsKwargs({args})"), } } } static UNDEFINED_CELL: PyOnceLock> = PyOnceLock::new(); #[pyclass(module = "pydantic_core._pydantic_core", frozen)] #[derive(Debug)] pub struct PydanticUndefinedType {} #[pymethods] impl PydanticUndefinedType { #[new] pub fn py_new(_py: Python) -> PyResult { Err(PyNotImplementedError::new_err( "Creating instances of \"UndefinedType\" is not supported", )) } #[staticmethod] #[pyo3(name = "new")] pub fn get(py: Python<'_>) -> &Py { UNDEFINED_CELL.get_or_init(py, || Py::new(py, PydanticUndefinedType {}).unwrap()) } fn __repr__(&self) -> &'static str { "PydanticUndefined" } fn __copy__(&self, py: Python) -> Py { UNDEFINED_CELL.get(py).unwrap().clone_ref(py) } #[pyo3(signature = (_memo, /))] fn __deepcopy__(&self, py: Python, _memo: &Bound<'_, PyAny>) -> Py { self.__copy__(py) } fn __reduce__(&self) -> &'static str { "PydanticUndefined" } } pydantic-pydantic-ba0aa01/pydantic-core/src/build_tools.rs000066400000000000000000000153351517143232300240320ustar00rootroot00000000000000use std::error::Error; use std::fmt; use std::ops::Deref; use std::str::FromStr; use std::sync::OnceLock; use pyo3::exceptions::PyException; use pyo3::prelude::*; use pyo3::types::{PyDict, PyList, PyString}; use pyo3::{PyErrArguments, intern}; use crate::ValidationError; use crate::errors::{PyLineError, ValError}; use crate::input::InputType; use crate::tools::SchemaDict; pub fn schema_or_config<'py, T>( schema: &Bound<'py, PyDict>, config: Option<&Bound<'py, PyDict>>, schema_key: &Bound<'py, PyString>, config_key: &Bound<'py, PyString>, ) -> PyResult> where T: FromPyObjectOwned<'py>, { match schema.get_as(schema_key)? { Some(v) => Ok(Some(v)), None => match config { Some(config) => config.get_as(config_key), None => Ok(None), }, } } pub fn schema_or_config_same<'py, T>( schema: &Bound<'py, PyDict>, config: Option<&Bound<'py, PyDict>>, key: &Bound<'py, PyString>, ) -> PyResult> where T: FromPyObjectOwned<'py>, { schema_or_config(schema, config, key, key) } pub fn is_strict(schema: &Bound<'_, PyDict>, config: Option<&Bound<'_, PyDict>>) -> PyResult { let py = schema.py(); Ok(schema_or_config_same(schema, config, intern!(py, "strict"))?.unwrap_or(false)) } enum SchemaErrorEnum { Message(String), ValidationError(ValidationError), } // we could perhaps do clever things here to store each schema error, or have different types for the top // level error group, and other errors, we could perhaps also support error groups!? #[pyclass(extends=PyException, module="pydantic_core._pydantic_core")] pub struct SchemaError(SchemaErrorEnum); impl fmt::Debug for SchemaError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "SchemaError({:?})", self.message()) } } impl fmt::Display for SchemaError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(self.message()) } } impl Error for SchemaError { #[cfg_attr(has_coverage_attribute, coverage(off))] fn source(&self) -> Option<&(dyn Error + 'static)> { None } } impl SchemaError { pub fn new_err(args: A) -> PyErr where A: PyErrArguments + Send + Sync + 'static, { PyErr::new::(args) } pub fn from_val_error(py: Python, error: ValError) -> PyErr { match error { ValError::LineErrors(raw_errors) => { let line_errors = match raw_errors .into_iter() .map(|e| PyLineError::from_val_line_error(py, e)) .collect::>() { Ok(errors) => errors, Err(err) => return err, }; let validation_error = ValidationError::new( line_errors, PyString::new(py, "Schema").into(), InputType::Python, false, ); let schema_error = SchemaError(SchemaErrorEnum::ValidationError(validation_error)); match Py::new(py, schema_error) { Ok(err) => PyErr::from_value(err.into_bound(py).into_any()), Err(err) => err, } } ValError::InternalErr(err) => err, ValError::Omit => Self::new_err("Unexpected Omit error."), ValError::UseDefault => Self::new_err("Unexpected UseDefault error."), } } fn message(&self) -> &str { match &self.0 { SchemaErrorEnum::Message(message) => message.as_str(), SchemaErrorEnum::ValidationError(_) => "", } } } #[pymethods] impl SchemaError { #[new] fn py_new(message: String) -> Self { Self(SchemaErrorEnum::Message(message)) } fn error_count(&self) -> usize { match &self.0 { SchemaErrorEnum::Message(_) => 0, SchemaErrorEnum::ValidationError(error) => error.error_count(), } } fn errors(&self, py: Python) -> PyResult> { match &self.0 { SchemaErrorEnum::Message(_) => Ok(PyList::empty(py).unbind()), SchemaErrorEnum::ValidationError(error) => error.errors(py, false, false, true), } } fn __str__(&self, py: Python) -> String { match &self.0 { SchemaErrorEnum::Message(message) => message.clone(), SchemaErrorEnum::ValidationError(error) => error.display(py, Some("Invalid Schema:"), false), } } fn __repr__(&self, py: Python) -> String { match &self.0 { SchemaErrorEnum::Message(message) => format!("SchemaError({message:?})"), SchemaErrorEnum::ValidationError(error) => error.display(py, Some("Invalid Schema:"), false), } } } macro_rules! py_schema_error_type { ($( $msg_args:expr ),+ ) => { crate::tools::py_error_type!(crate::build_tools::SchemaError; $( $msg_args ),+) }; } pub(crate) use py_schema_error_type; macro_rules! py_schema_err { ($( $msg_args:expr ),+ ) => { Err(crate::build_tools::py_schema_error_type!($( $msg_args ),+)) }; } pub(crate) use py_schema_err; #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum ExtraBehavior { Allow, Forbid, Ignore, } impl ExtraBehavior { pub fn from_schema_or_config( py: Python, schema: &Bound<'_, PyDict>, config: Option<&Bound<'_, PyDict>>, default: Self, ) -> PyResult { let extra_behavior = schema_or_config::>>( schema, config, intern!(py, "extra_behavior"), intern!(py, "extra_fields_behavior"), )? .flatten(); let res = match extra_behavior.as_ref().map(|s| s.to_str()).transpose()? { Some(s) => Self::from_str(s)?, None => default, }; Ok(res) } } impl FromStr for ExtraBehavior { type Err = PyErr; fn from_str(s: &str) -> Result { match s { "allow" => Ok(Self::Allow), "forbid" => Ok(Self::Forbid), "ignore" => Ok(Self::Ignore), s => py_schema_err!("Invalid extra_behavior: `{s}`"), } } } /// A lazily-initialized value. /// /// This is a basic replacement for `LazyLock` which is available only in Rust 1.80+. pub struct LazyLock { init: fn() -> T, value: OnceLock, } impl Deref for LazyLock { type Target = T; fn deref(&self) -> &Self::Target { self.value.get_or_init(self.init) } } impl LazyLock { pub const fn new(init: fn() -> T) -> Self { Self { init, value: OnceLock::new(), } } } pydantic-pydantic-ba0aa01/pydantic-core/src/common/000077500000000000000000000000001517143232300224265ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/pydantic-core/src/common/missing_sentinel.rs000066400000000000000000000007571517143232300263570ustar00rootroot00000000000000use pyo3::intern; use pyo3::prelude::*; use pyo3::sync::PyOnceLock; static MISSING_SENTINEL_OBJECT: PyOnceLock> = PyOnceLock::new(); pub fn get_missing_sentinel_object(py: Python<'_>) -> &Bound<'_, PyAny> { MISSING_SENTINEL_OBJECT .get_or_init(py, || { py.import(intern!(py, "pydantic_core")) .and_then(|core_module| core_module.getattr(intern!(py, "MISSING"))) .unwrap() .into() }) .bind(py) } pydantic-pydantic-ba0aa01/pydantic-core/src/common/mod.rs000066400000000000000000000001201517143232300235440ustar00rootroot00000000000000pub(crate) mod missing_sentinel; pub(crate) mod prebuilt; pub(crate) mod union; pydantic-pydantic-ba0aa01/pydantic-core/src/common/prebuilt.rs000066400000000000000000000033311517143232300246220ustar00rootroot00000000000000use pyo3::intern; use pyo3::prelude::*; use pyo3::types::{PyAny, PyDict, PyType}; use crate::tools::SchemaDict; pub fn get_prebuilt( type_: &str, schema: &Bound<'_, PyDict>, prebuilt_attr_name: &str, extractor: impl FnOnce(Bound<'_, PyAny>) -> PyResult>, ) -> PyResult> { let py = schema.py(); // we can only use prebuilt validators/serializers from models and Pydantic dataclasses. // However, we don't want to use a prebuilt structure from dataclasses if we have a `generic_origin` // as this means the dataclass was parametrized (so a generic alias instance), and `cls` in the // core schema is still the (unparametrized) class, meaning we would fetch the wrong validator/serializer. if !matches!(type_, "model" | "dataclass") || (type_ == "dataclass" && schema.contains(intern!(py, "generic_origin"))?) { return Ok(None); } let class: Bound<'_, PyType> = schema.get_as_req(intern!(py, "cls"))?; // Note: we NEED to use the __dict__ here (and perform get_item calls rather than getattr) // because we don't want to fetch prebuilt validators from parent classes. // We don't downcast here because __dict__ on a class is a readonly mappingproxy, // so we can just leave it as is and do get_item checks. let class_dict = class.getattr(intern!(py, "__dict__"))?; let is_complete: bool = class_dict .get_item(intern!(py, "__pydantic_complete__")) .is_ok_and(|b| b.extract().unwrap_or(false)); if !is_complete { return Ok(None); } // Retrieve the prebuilt validator / serializer if available let prebuilt: Bound<'_, PyAny> = class_dict.get_item(prebuilt_attr_name)?; extractor(prebuilt) } pydantic-pydantic-ba0aa01/pydantic-core/src/common/union.rs000066400000000000000000000024771517143232300241360ustar00rootroot00000000000000use pyo3::prelude::*; use pyo3::{PyTraverseError, PyVisit}; use smallvec::SmallVec; use crate::lookup_key::{LookupPath, ValidationAlias}; use crate::py_gc::PyGcTraverse; #[derive(Debug)] pub enum Discriminator { /// use `LookupPaths` to find the tag, same as we do to find values in typed_dict aliases LookupPaths(SmallVec<[LookupPath; 1]>), /// call a function to find the tag to use Function(Py), } impl Discriminator { pub fn new(raw: &Bound<'_, PyAny>) -> PyResult { if raw.is_callable() { return Ok(Self::Function(raw.clone().unbind())); } let lookup: ValidationAlias = raw.extract()?; Ok(Self::LookupPaths(lookup.into_paths())) } pub fn to_string_py(&self, py: Python) -> PyResult { match self { Self::Function(f) => Ok(format!("{}()", f.getattr(py, "__name__")?)), Self::LookupPaths(paths) => Ok(paths.iter().map(ToString::to_string).collect::>().join(" | ")), } } } impl PyGcTraverse for Discriminator { fn py_gc_traverse(&self, visit: &PyVisit<'_>) -> Result<(), PyTraverseError> { match self { Self::Function(obj) => visit.call(obj)?, Self::LookupPaths(_) => {} } Ok(()) } } pub(crate) const SMALL_UNION_THRESHOLD: usize = 4; pydantic-pydantic-ba0aa01/pydantic-core/src/definitions.rs000066400000000000000000000216301517143232300240210ustar00rootroot00000000000000/// Definition / reference management /// Our definitions system is very similar to json schema's: there's ref strings and a definitions section /// Unlike json schema we let you put definitions inline, not just in a single '#/$defs/' block or similar. /// We use DefinitionsBuilder to collect the references / definitions into a single vector /// and then get a definition from a reference using an integer id (just for performance of not using a HashMap) use std::{ borrow::Borrow, collections::hash_map::Entry, fmt::Debug, sync::{ Arc, OnceLock, Weak, atomic::{AtomicBool, Ordering}, }, }; use pyo3::{PyTraverseError, PyVisit, prelude::*}; use ahash::AHashMap; use crate::{build_tools::py_schema_err, py_gc::PyGcTraverse}; /// Definitions are validators and serializers that are /// shared by reference. /// They come into play whenever there is recursion, e.g. /// if you have validators A -> B -> A then A will be shared /// by reference so that the SchemaValidator itself can own it. /// These primarily get used by DefinitionRefValidator and DefinitionRefSerializer, /// other validators / serializers primarily pass them around without interacting with them. /// They get indexed by a ReferenceId, which are integer identifiers /// that are handed out and managed by DefinitionsBuilder when the Schema{Validator,Serializer} /// gets build. pub struct Definitions(AHashMap, Definition>); struct Definition { value: Arc>, name: Arc, } /// Reference to a definition. pub struct DefinitionRef { reference: Arc, // We use a weak reference to the definition to avoid a reference cycle // when recursive definitions are used. value: Weak>, name: Arc, } // DefinitionRef can always be cloned (#[derive(Clone)] would require T: Clone) impl Clone for DefinitionRef { fn clone(&self) -> Self { Self { reference: self.reference.clone(), value: self.value.clone(), name: self.name.clone(), } } } impl DefinitionRef { pub fn id(&self) -> usize { Weak::as_ptr(&self.value) as usize } pub fn get_or_init_name(&self, init: impl FnOnce(&T) -> String) -> &str { let Some(definition) = self.value.upgrade() else { return "..."; }; match definition.get() { Some(value) => self.name.get_or_init(|| init(value)), None => "...", } } pub fn read(&self, f: impl FnOnce(Option<&T>) -> R) -> R { f(self.value.upgrade().as_ref().and_then(|value| value.get())) } } impl Debug for DefinitionRef { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // To avoid possible infinite recursion from recursive definitions, // a DefinitionRef just displays debug as its name self.name.fmt(f) } } impl Debug for Definitions { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // Formatted as a list for backwards compatibility; in principle // this could be formatted as a map. Maybe change in a future // minor release of pydantic. write![f, "["]?; let mut first = true; for def in self.0.values() { write![f, "{sep}{def:?}", sep = if first { "" } else { ", " }]?; first = false; } write![f, "]"]?; Ok(()) } } impl Debug for Definition { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self.value.get() { Some(value) => value.fmt(f), None => "...".fmt(f), } } } impl PyGcTraverse for DefinitionRef { fn py_gc_traverse(&self, visit: &PyVisit<'_>) -> Result<(), PyTraverseError> { if let Some(value) = self.value.upgrade().as_ref().and_then(|v| v.get()) { value.py_gc_traverse(visit)?; } Ok(()) } } impl PyGcTraverse for Definitions { fn py_gc_traverse(&self, visit: &PyVisit<'_>) -> Result<(), PyTraverseError> { for value in self.0.values() { if let Some(value) = value.value.get() { value.py_gc_traverse(visit)?; } } Ok(()) } } #[derive(Debug)] pub struct DefinitionsBuilder { definitions: Definitions, use_prebuilt: bool, } impl DefinitionsBuilder { pub fn new(use_prebuilt: bool) -> Self { Self { definitions: Definitions(AHashMap::new()), use_prebuilt, } } /// Whether prebuilt validators/serializers should be used pub fn use_prebuilt(&self) -> bool { self.use_prebuilt } /// Get a ReferenceId for the given reference string. pub fn get_definition(&mut self, reference: &str) -> DefinitionRef { // We either need a String copy or two hashmap lookups // Neither is better than the other // We opted for the easier outward facing API let reference = Arc::new(reference.to_string()); let value = match self.definitions.0.entry(reference.clone()) { Entry::Occupied(entry) => entry.into_mut(), Entry::Vacant(entry) => entry.insert(Definition { value: Arc::new(OnceLock::new()), name: Arc::new(LazyName::new()), }), }; DefinitionRef { reference, value: Arc::downgrade(&value.value), name: value.name.clone(), } } /// Add a definition, returning the ReferenceId that maps to it pub fn add_definition(&mut self, reference: String, value: T) -> PyResult> { let reference = Arc::new(reference); let value = match self.definitions.0.entry(reference.clone()) { Entry::Occupied(entry) => { let definition = entry.into_mut(); match definition.value.set(value) { Ok(()) => definition, Err(_) => return py_schema_err!("Duplicate ref: `{reference}`"), } } Entry::Vacant(entry) => entry.insert(Definition { value: Arc::new(OnceLock::from(value)), name: Arc::new(LazyName::new()), }), }; Ok(DefinitionRef { reference, value: Arc::downgrade(&value.value), name: value.name.clone(), }) } /// Consume this Definitions into a vector of items, indexed by each items ReferenceId pub fn finish(self) -> PyResult> { for (reference, def) in &self.definitions.0 { if def.value.get().is_none() { return py_schema_err!("Definitions error: definition `{reference}` was never filled"); } } Ok(self.definitions) } } /// Because definitions can create recursive structures, we often need to be able to populate /// values lazily from these structures in a way that avoids infinite recursion. This structure /// avoids infinite recursion by returning a default value when a recursion loop is detected. pub(crate) struct RecursionSafeCache { cache: OnceLock, in_recursion: AtomicBool, } impl Clone for RecursionSafeCache { fn clone(&self) -> Self { Self { cache: self.cache.clone(), in_recursion: AtomicBool::new(false), } } } impl RecursionSafeCache { /// Creates a new RecursionSafeCache pub(crate) fn new() -> Self { Self { cache: OnceLock::new(), in_recursion: AtomicBool::new(false), } } /// Gets or initialized the cached value, returning the default in the case of recursion loops pub(crate) fn get_or_init(&self, init: impl FnOnce() -> T, recursive_default: &'static D) -> &D where T: Borrow, { if let Some(cached) = self.cache.get() { return cached.borrow(); } if self .in_recursion .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst) .is_err() { return recursive_default; } let result = self.cache.get_or_init(init).borrow(); self.in_recursion.store(false, Ordering::SeqCst); result } /// Gets the value, if it is set fn get(&self) -> Option<&T> { self.cache.get() } } #[derive(Clone)] struct LazyName(RecursionSafeCache); impl LazyName { fn new() -> Self { Self(RecursionSafeCache::new()) } /// Gets the validator name, returning the default in the case of recursion loops fn get_or_init(&self, init: impl FnOnce() -> String) -> &str { self.0.get_or_init(init, "...") } } impl Debug for LazyName { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.0.get().map_or("...", String::as_str).fmt(f) } } pydantic-pydantic-ba0aa01/pydantic-core/src/errors/000077500000000000000000000000001517143232300224525ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/pydantic-core/src/errors/line_error.rs000066400000000000000000000116641517143232300251700ustar00rootroot00000000000000use std::convert::Infallible; use pyo3::CastError; use pyo3::CastIntoError; use pyo3::exceptions::PyTypeError; use pyo3::prelude::*; use jiter::JsonValue; use crate::input::BorrowInput; use crate::input::Input; use super::location::{LocItem, Location}; use super::types::ErrorType; pub type ValResult = Result; pub trait ToErrorValue { fn to_error_value(&self) -> InputValue; } impl<'a, T: BorrowInput<'a>> ToErrorValue for T { fn to_error_value(&self) -> InputValue { Input::as_error_value(self.borrow_input()) } } impl ToErrorValue for &'_ dyn ToErrorValue { fn to_error_value(&self) -> InputValue { (**self).to_error_value() } } #[cfg_attr(debug_assertions, derive(Debug))] pub enum ValError { LineErrors(Vec), InternalErr(PyErr), Omit, UseDefault, } impl From for ValError { fn from(py_err: PyErr) -> Self { Self::InternalErr(py_err) } } impl From> for ValError { fn from(py_downcast: CastError) -> Self { Self::InternalErr(PyTypeError::new_err(py_downcast.to_string())) } } impl From> for ValError { fn from(py_downcast: CastIntoError) -> Self { Self::InternalErr(PyTypeError::new_err(py_downcast.to_string())) } } impl From> for ValError { fn from(line_errors: Vec) -> Self { Self::LineErrors(line_errors) } } impl From for ValError { fn from(infallible: Infallible) -> Self { match infallible {} } } impl ValError { pub fn new(error_type: ErrorType, input: impl ToErrorValue) -> ValError { Self::LineErrors(vec![ValLineError::new(error_type, input)]) } pub fn new_with_loc(error_type: ErrorType, input: impl ToErrorValue, loc: impl Into) -> ValError { Self::LineErrors(vec![ValLineError::new_with_loc(error_type, input, loc)]) } pub fn new_custom_input(error_type: ErrorType, input_value: InputValue) -> ValError { Self::LineErrors(vec![ValLineError::new_custom_input(error_type, input_value)]) } /// helper function to call with_outer on line items if applicable pub fn with_outer_location(self, into_loc_item: impl Into) -> Self { let loc_item = into_loc_item.into(); match self { Self::LineErrors(mut line_errors) => { for line_error in &mut line_errors { line_error.location.with_outer(loc_item.clone()); } Self::LineErrors(line_errors) } other => other, } } } /// A `ValLineError` is a single error that occurred during validation which is converted to a `PyLineError` /// to eventually form a `ValidationError`. /// I don't like the name `ValLineError`, but it's the best I could come up with (for now). #[cfg_attr(debug_assertions, derive(Debug))] pub struct ValLineError { pub error_type: ErrorType, // location is reversed so that adding an "outer" location item is pushing, it's reversed before showing to the user pub location: Location, pub input_value: InputValue, } impl ValLineError { pub fn new(error_type: ErrorType, input: impl ToErrorValue) -> ValLineError { Self { error_type, input_value: input.to_error_value(), location: Location::default(), } } pub fn new_with_loc(error_type: ErrorType, input: impl ToErrorValue, loc: impl Into) -> ValLineError { Self { error_type, input_value: input.to_error_value(), location: Location::new_some(loc.into()), } } pub fn new_with_full_loc(error_type: ErrorType, input: impl ToErrorValue, location: Location) -> ValLineError { Self { error_type, input_value: input.to_error_value(), location, } } pub fn new_custom_input(error_type: ErrorType, input_value: InputValue) -> ValLineError { Self { error_type, input_value, location: Location::default(), } } /// location is stored reversed so it's quicker to add "outer" items as that's what we always do /// hence `push` here instead of `insert` pub fn with_outer_location(mut self, into_loc_item: impl Into) -> Self { self.location.with_outer(into_loc_item.into()); self } // change the error_type on a error in place pub fn with_type(mut self, error_type: ErrorType) -> Self { self.error_type = error_type; self } pub fn first_loc_item(&self) -> Option<&LocItem> { match &self.location { Location::Empty => None, // last because order is reversed Location::List(loc_items) => loc_items.last(), } } } #[cfg_attr(debug_assertions, derive(Debug))] #[derive(Clone, IntoPyObject)] pub enum InputValue { Python(Py), Json(JsonValue<'static>), } pydantic-pydantic-ba0aa01/pydantic-core/src/errors/location.rs000066400000000000000000000137331517143232300246370ustar00rootroot00000000000000use pyo3::exceptions::PyTypeError; use pyo3::pybacked::PyBackedStr; use pyo3::sync::PyOnceLock; use std::fmt; use pyo3::prelude::*; use pyo3::types::{PyList, PyTuple}; use serde::ser::SerializeSeq; use serde::{Serialize, Serializer}; /// Used to store individual items of the error location, e.g. a string for key/field names /// or a number for array indices. #[derive(Clone, Eq, PartialEq, IntoPyObjectRef)] #[cfg_attr(debug_assertions, derive(Debug))] pub enum LocItem { /// string type key, used to identify items from a dict or anything that implements `__getitem__` S(String), /// Python-owned variant of the above PyS(PyBackedStr), /// integer key, used to get: /// * items from a list /// * items from a tuple /// * dict with int keys `dict[int, ...]` (python only) /// * with integer keys in tagged unions I(i64), } impl fmt::Display for LocItem { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::S(s) if s.contains('.') => write!(f, "`{s}`"), Self::S(s) => write!(f, "{s}"), Self::PyS(s) if s.contains('.') => write!(f, "`{s}`"), Self::PyS(s) => write!(f, "{s}"), Self::I(i) => write!(f, "{i}"), } } } impl From for LocItem { fn from(s: String) -> Self { Self::S(s) } } impl From<&str> for LocItem { fn from(s: &str) -> Self { Self::S(s.to_string()) } } impl From for LocItem { fn from(i: i64) -> Self { Self::I(i) } } impl From for LocItem { fn from(u: usize) -> Self { Self::I(u as i64) } } impl From for LocItem { fn from(s: PyBackedStr) -> Self { Self::PyS(s) } } impl Serialize for LocItem { fn serialize(&self, serializer: S) -> Result where S: Serializer, { match self { Self::S(s) => serializer.serialize_str(s.as_str()), Self::PyS(s) => serializer.serialize_str(s), Self::I(loc) => serializer.serialize_i64(*loc), } } } /// Error locations are represented by a vector of `LocItem`s. /// e.g. if the error occurred in the third member of a list called `foo`, /// the location would be `["foo", 2]`. /// Note: location in List is stored in **REVERSE** so adding an "outer" item to location involves /// pushing to the vec which is faster than inserting and shifting everything along. /// Then when "using" location in `Display` and `ToPyObject` order has to be reversed #[derive(Clone, Default)] #[cfg_attr(debug_assertions, derive(Debug))] pub enum Location { // no location, avoid creating an unnecessary vec #[default] Empty, // store the in a vec of LocItems, Note: this is the REVERSE of location, see above // we could perhaps use a smallvec or similar here, probably only worth it if we store a Cow in LocItem List(Vec), } static EMPTY_TUPLE: PyOnceLock> = PyOnceLock::new(); impl<'py> IntoPyObject<'py> for &'_ Location { type Target = PyTuple; type Output = Bound<'py, PyTuple>; type Error = PyErr; fn into_pyobject(self, py: Python<'py>) -> PyResult> { match self { Location::List(loc) => PyTuple::new(py, loc.iter().rev()), Location::Empty => Ok(EMPTY_TUPLE .get_or_init(py, || PyTuple::empty(py).unbind()) .bind(py) .clone()), } } } impl fmt::Display for Location { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::List(loc) => { let loc_str = loc.iter().rev().map(ToString::to_string).collect::>(); writeln!(f, "{}", loc_str.join(".")) } Self::Empty => Ok(()), } } } impl Location { /// create a new location vec with a value, 3 is plucked out of thin air, should it just be 1? pub fn new_some(item: LocItem) -> Self { let mut loc = Vec::with_capacity(3); loc.push(item); Self::List(loc) } pub fn with_outer(&mut self, loc_item: LocItem) { match self { Self::List(loc) => loc.push(loc_item), Self::Empty => { *self = Self::new_some(loc_item); } } } } impl Serialize for Location { fn serialize(&self, serializer: S) -> Result where S: Serializer, { match self { Self::Empty => serializer.serialize_seq(Some(0))?.end(), Self::List(loc) => { let mut seq = serializer.serialize_seq(Some(loc.len()))?; for e in loc.iter().rev() { seq.serialize_element(e)?; } seq.end() } } } } impl TryFrom>> for Location { type Error = PyErr; /// Only ever called by ValidationError -> PyLineError to convert user input to our internal Location /// Thus this expects the location to *not* be reversed and reverses it before storing it. fn try_from(location: Option<&Bound<'_, PyAny>>) -> PyResult { if let Some(location) = location { let mut loc_vec: Vec = if let Ok(tuple) = location.cast::() { tuple.iter().map(Into::into).collect() } else if let Ok(list) = location.cast::() { list.iter().map(Into::into).collect() } else { return Err(PyTypeError::new_err( "Location must be a list or tuple of strings and ints", )); }; if loc_vec.is_empty() { Ok(Self::Empty) } else { // Don't force Python users to give use the location reversed // just be we internally store it like that loc_vec.reverse(); Ok(Self::List(loc_vec)) } } else { Ok(Self::Empty) } } } pydantic-pydantic-ba0aa01/pydantic-core/src/errors/mod.rs000066400000000000000000000021461517143232300236020ustar00rootroot00000000000000use pyo3::prelude::*; mod line_error; mod location; mod types; mod validation_exception; mod value_exception; pub use self::line_error::{InputValue, ToErrorValue, ValError, ValLineError, ValResult}; pub use self::location::{LocItem, Location}; pub use self::types::{ErrorType, ErrorTypeDefaults, Number, list_all_errors}; pub use self::validation_exception::{PyLineError, ValidationError}; pub use self::value_exception::{PydanticCustomError, PydanticKnownError, PydanticOmit, PydanticUseDefault}; pub fn py_err_string(py: Python, err: PyErr) -> String { let value = err.value(py); match value.get_type().qualname() { Ok(type_name) => match value.str() { Ok(py_str) => { let str_cow = py_str.to_string_lossy(); let str = str_cow.as_ref(); if !str.is_empty() { format!("{type_name}: {str}") } else { type_name.to_string() } } Err(_) => format!("{type_name}: "), }, Err(_) => "Unknown Error".to_string(), } } pydantic-pydantic-ba0aa01/pydantic-core/src/errors/types.rs000066400000000000000000001055401517143232300241710ustar00rootroot00000000000000use std::any::type_name; use std::borrow::Cow; use std::fmt; use pyo3::exceptions::{PyKeyError, PyTypeError}; use pyo3::prelude::*; use pyo3::sync::PyOnceLock; use pyo3::types::{PyDict, PyList}; use ahash::AHashMap; use num_bigint::BigInt; use strum::{Display, EnumMessage, IntoEnumIterator}; use strum_macros::EnumIter; use crate::input::{InputType, Int}; use crate::tools::{py_err, py_error_type}; use super::PydanticCustomError; #[pyfunction] pub fn list_all_errors(py: Python<'_>) -> PyResult> { let mut errors: Vec> = Vec::with_capacity(100); for error_type in ErrorType::iter() { if !matches!(error_type, ErrorType::CustomError { .. }) { let d = PyDict::new(py); d.set_item("type", error_type.to_string())?; let message_template_python = error_type.message_template_python(); d.set_item("message_template_python", message_template_python)?; d.set_item( "example_message_python", error_type.render_message(py, InputType::Python)?, )?; let message_template_json = error_type.message_template_json(); if message_template_python != message_template_json { d.set_item("message_template_json", message_template_json)?; d.set_item("example_message_json", error_type.render_message(py, InputType::Json)?)?; } d.set_item("example_context", error_type.py_dict(py)?)?; errors.push(d); } } PyList::new(py, errors) } fn field_from_context<'py, T: FromPyObjectOwned<'py>>( context: Option<&Bound<'py, PyDict>>, field_name: &str, enum_name: &str, type_name_fn: fn() -> &'static str, ) -> PyResult { context .ok_or_else(|| py_error_type!(PyTypeError; "{enum_name}: '{field_name}' required in context"))? .get_item(field_name)? .ok_or_else(|| py_error_type!(PyTypeError; "{enum_name}: '{field_name}' required in context"))? .extract::() .map_err( |_| py_error_type!(PyTypeError; "{enum_name}: '{field_name}' context value must be a {}", type_name_fn()), ) } fn cow_field_from_context<'py, T: FromPyObjectOwned<'py>, B: ToOwned + ?Sized + 'static>( context: Option<&Bound<'py, PyDict>>, field_name: &str, enum_name: &str, _type_name_fn: fn() -> &'static str, ) -> PyResult> { let res: T = field_from_context(context, field_name, enum_name, || { type_name::().split("::").last().unwrap() })?; Ok(Cow::Owned(res)) } macro_rules! basic_error_default { ( $item:ident $(,)? ) => { pub const $item: ErrorType = ErrorType::$item { context: None }; }; ( $item:ident, $($key:ident),* $(,)? ) => {}; // With more parameters enum item must be explicitly created } macro_rules! error_types { ( $( $item:ident { $($key:ident: {ctx_type: $ctx_type:ty, ctx_fn: $ctx_fn:path}),* $(,)? }, )+ ) => { #[derive(Clone, Debug, Display, EnumMessage, EnumIter)] #[strum(serialize_all = "snake_case")] pub enum ErrorType { $( $item { context: Option>, $($key: $ctx_type,)* } ),+, } impl ErrorType { pub fn new(py: Python, value: &str, context: Option>) -> PyResult { let lookup = ERROR_TYPE_LOOKUP.get_or_init(py, Self::build_lookup); let error_type = match lookup.get(value) { Some(error_type) => error_type.clone(), None => return py_err!(PyKeyError; "Invalid error type: '{value}'"), }; match error_type { $( Self::$item { .. } => { Ok(Self::$item { $( $key: $ctx_fn(context.as_ref(), stringify!($key), stringify!($item), || stringify!($ctx_type))?, )* context: context.map(|c| c.unbind()), }) }, )+ } } fn py_dict_update_ctx(&self, py: Python, dict: &Bound<'_, PyDict>) -> PyResult { use pyo3::types::PyMapping; match self { $( Self::$item { context, $($key,)* } => { $( dict.set_item(stringify!($key), $key)?; )* if let Some(ctx) = context { dict.update(ctx.bind(py).cast::()?)?; Ok(true) } else { Ok(false) } }, )+ } } } pub struct ErrorTypeDefaults {} // Allow unused default constants as they are generated by macro. // Also allow camel case as constants so we dont need to do case conversion of macro // generated names. Enums are also then easier to find when searching. #[allow(dead_code, non_upper_case_globals)] impl ErrorTypeDefaults { $( basic_error_default!($item, $($key),*); )+ } }; } // Definite each validation error. // NOTE: if an error has parameters: // * the variables in the message need to match the enum struct // * you need to add an entry to the `render` enum to render the error message as a template error_types! { // --------------------- // Assignment errors NoSuchAttribute { attribute: {ctx_type: String, ctx_fn: field_from_context}, }, // --------------------- // JSON errors JsonInvalid { error: {ctx_type: String, ctx_fn: field_from_context}, }, JsonType {}, NeedsPythonObject { method_name: {ctx_type: String, ctx_fn: field_from_context} }, // --------------------- // recursion error RecursionLoop {}, // --------------------- // typed dict specific errors Missing {}, FrozenField {}, FrozenInstance {}, ExtraForbidden {}, InvalidKey {}, GetAttributeError { error: {ctx_type: String, ctx_fn: field_from_context}, }, // --------------------- // model class specific errors ModelType { class_name: {ctx_type: String, ctx_fn: field_from_context}, }, ModelAttributesType {}, // --------------------- // dataclass errors (we don't talk about ArgsKwargs here for simplicity) DataclassType { class_name: {ctx_type: String, ctx_fn: field_from_context}, }, DataclassExactType { class_name: {ctx_type: String, ctx_fn: field_from_context}, }, // --------------------- // Default factory not called (happens when there's already an error and the factory takes data) DefaultFactoryNotCalled {}, // --------------------- // None errors NoneRequired {}, // --------------------- // generic comparison errors GreaterThan { gt: {ctx_type: Number, ctx_fn: field_from_context}, }, GreaterThanEqual { ge: {ctx_type: Number, ctx_fn: field_from_context}, }, LessThan { lt: {ctx_type: Number, ctx_fn: field_from_context}, }, LessThanEqual { le: {ctx_type: Number, ctx_fn: field_from_context}, }, MultipleOf { multiple_of: {ctx_type: Number, ctx_fn: field_from_context}, }, FiniteNumber {}, // --------------------- // generic length errors - used for everything with a length except strings and bytes which need custom messages TooShort { field_type: {ctx_type: String, ctx_fn: field_from_context}, min_length: {ctx_type: usize, ctx_fn: field_from_context}, actual_length: {ctx_type: usize, ctx_fn: field_from_context}, }, TooLong { field_type: {ctx_type: String, ctx_fn: field_from_context}, max_length: {ctx_type: usize, ctx_fn: field_from_context}, actual_length: {ctx_type: Option, ctx_fn: field_from_context}, }, // --------------------- // generic collection and iteration errors IterableType {}, IterationError { error: {ctx_type: String, ctx_fn: field_from_context}, }, // --------------------- // string errors StringType {}, StringSubType {}, StringUnicode {}, StringTooShort { min_length: {ctx_type: usize, ctx_fn: field_from_context}, }, StringTooLong { max_length: {ctx_type: usize, ctx_fn: field_from_context}, }, StringPatternMismatch { pattern: {ctx_type: String, ctx_fn: field_from_context}, }, StringNotAscii {}, // --------------------- // enum errors Enum { expected: {ctx_type: String, ctx_fn: field_from_context}, }, // --------------------- // dict errors DictType {}, MappingType { error: {ctx_type: Cow<'static, str>, ctx_fn: cow_field_from_context}, }, // --------------------- // list errors ListType {}, // --------------------- // tuple errors TupleType {}, // --------------------- // set errors SetType {}, SetItemNotHashable {}, // --------------------- // bool errors BoolType {}, BoolParsing {}, // --------------------- // int errors IntType {}, IntParsing {}, IntParsingSize {}, IntFromFloat {}, // --------------------- // float errors FloatType {}, FloatParsing {}, // --------------------- // bytes errors BytesType {}, BytesTooShort { min_length: {ctx_type: usize, ctx_fn: field_from_context}, }, BytesTooLong { max_length: {ctx_type: usize, ctx_fn: field_from_context}, }, BytesInvalidEncoding { encoding: {ctx_type: String, ctx_fn: field_from_context}, encoding_error: {ctx_type: String, ctx_fn: field_from_context}, }, // --------------------- // python errors from functions ValueError { error: {ctx_type: Option>, ctx_fn: field_from_context}, // Use Option because EnumIter requires Default to be implemented }, AssertionError { error: {ctx_type: Option>, ctx_fn: field_from_context}, // Use Option because EnumIter requires Default to be implemented }, // Note: strum message and serialize are not used here CustomError { // context is a common field in all enums error_type: {ctx_type: String, ctx_fn: field_from_context}, message_template: {ctx_type: String, ctx_fn: field_from_context}, }, // --------------------- // literals LiteralError { expected: {ctx_type: String, ctx_fn: field_from_context}, }, // --------------------- // missing sentinel MissingSentinelError {}, // date errors DateType {}, DateParsing { error: {ctx_type: Cow<'static, str>, ctx_fn: cow_field_from_context}, }, DateFromDatetimeParsing { error: {ctx_type: Cow<'static, str>, ctx_fn: cow_field_from_context}, }, DateFromDatetimeInexact {}, DatePast {}, DateFuture {}, // --------------------- // date errors TimeType {}, TimeParsing { error: {ctx_type: Cow<'static, str>, ctx_fn: cow_field_from_context}, }, // --------------------- // datetime errors DatetimeType {}, DatetimeParsing { error: {ctx_type: Cow<'static, str>, ctx_fn: cow_field_from_context}, }, DatetimeObjectInvalid { error: {ctx_type: String, ctx_fn: field_from_context}, }, DatetimeFromDateParsing { error: {ctx_type: Cow<'static, str>, ctx_fn: cow_field_from_context}, }, DatetimePast {}, DatetimeFuture {}, // --------------------- // timezone errors TimezoneNaive {}, TimezoneAware {}, TimezoneOffset { tz_expected: {ctx_type: i32, ctx_fn: field_from_context}, tz_actual: {ctx_type: i32, ctx_fn: field_from_context}, }, // --------------------- // timedelta errors TimeDeltaType {}, TimeDeltaParsing { error: {ctx_type: Cow<'static, str>, ctx_fn: cow_field_from_context}, }, // --------------------- // frozenset errors FrozenSetType {}, // --------------------- // introspection types - e.g. isinstance, callable IsInstanceOf { class: {ctx_type: String, ctx_fn: field_from_context}, }, IsSubclassOf { class: {ctx_type: String, ctx_fn: field_from_context}, }, CallableType {}, // --------------------- // union errors UnionTagInvalid { discriminator: {ctx_type: String, ctx_fn: field_from_context}, tag: {ctx_type: String, ctx_fn: field_from_context}, expected_tags: {ctx_type: String, ctx_fn: field_from_context}, }, UnionTagNotFound { discriminator: {ctx_type: String, ctx_fn: field_from_context}, }, // --------------------- // argument errors ArgumentsType {}, MissingArgument {}, UnexpectedKeywordArgument {}, MissingKeywordOnlyArgument {}, UnexpectedPositionalArgument {}, MissingPositionalOnlyArgument {}, MultipleArgumentValues {}, // --------------------- // URL errors UrlType {}, UrlParsing { // would be great if this could be a static cow, waiting for https://github.com/servo/rust-url/issues/801 error: {ctx_type: String, ctx_fn: field_from_context}, }, UrlSyntaxViolation { error: {ctx_type: Cow<'static, str>, ctx_fn: cow_field_from_context}, }, UrlTooLong { max_length: {ctx_type: usize, ctx_fn: field_from_context}, }, UrlScheme { expected_schemes: {ctx_type: String, ctx_fn: field_from_context}, }, // UUID errors, UuidType {}, UuidParsing { error: {ctx_type: String, ctx_fn: field_from_context}, }, UuidVersion { expected_version: {ctx_type: usize, ctx_fn: field_from_context}, }, // Decimal errors DecimalType {}, DecimalParsing {}, DecimalMaxDigits { max_digits: {ctx_type: u64, ctx_fn: field_from_context}, }, DecimalMaxPlaces { decimal_places: {ctx_type: u64, ctx_fn: field_from_context}, }, DecimalWholeDigits { whole_digits: {ctx_type: u64, ctx_fn: field_from_context}, }, // Complex errors ComplexType {}, ComplexStrParsing {}, } macro_rules! render { ($template:ident, $($value:ident),* $(,)?) => { Ok( $template $( .replace(concat!("{", stringify!($value), "}"), $value) )* ) }; } macro_rules! to_string_render { ($template:ident, $($value:ident),* $(,)?) => { Ok( $template $( .replace(concat!("{", stringify!($value), "}"), &$value.to_string()) )* ) }; } fn plural_s + PartialEq>(value: T) -> &'static str { if value == 1.into() { "" } else { "s" } } static ERROR_TYPE_LOOKUP: PyOnceLock> = PyOnceLock::new(); impl ErrorType { pub fn new_custom_error(py: Python, custom_error: PydanticCustomError) -> Self { Self::CustomError { error_type: custom_error.error_type().to_owned(), message_template: custom_error.message_template().to_owned(), context: custom_error.context(py), } } pub fn message_template_python(&self) -> &'static str { #[allow(clippy::match_same_arms)] // much nicer to have the messages explicitly listed match self { Self::NoSuchAttribute { .. } => "Object has no attribute '{attribute}'", Self::JsonInvalid { .. } => "Invalid JSON: {error}", Self::JsonType { .. } => "JSON input should be string, bytes or bytearray", Self::NeedsPythonObject { .. } => { "Cannot check `{method_name}` when validating from json, use a JsonOrPython validator instead" } Self::RecursionLoop { .. } => "Recursion error - cyclic reference detected", Self::Missing { .. } => "Field required", Self::FrozenField { .. } => "Field is frozen", Self::FrozenInstance { .. } => "Instance is frozen", Self::ExtraForbidden { .. } => "Extra inputs are not permitted", Self::InvalidKey { .. } => "Keys should be strings", Self::GetAttributeError { .. } => "Error extracting attribute: {error}", Self::ModelType { .. } => "Input should be a valid dictionary or instance of {class_name}", Self::ModelAttributesType { .. } => "Input should be a valid dictionary or object to extract fields from", Self::DataclassType { .. } => "Input should be a dictionary or an instance of {class_name}", Self::DataclassExactType { .. } => "Input should be an instance of {class_name}", Self::DefaultFactoryNotCalled { .. } => { "The default factory uses validated data, but at least one validation error occurred" } Self::NoneRequired { .. } => "Input should be None", Self::GreaterThan { .. } => "Input should be greater than {gt}", Self::GreaterThanEqual { .. } => "Input should be greater than or equal to {ge}", Self::LessThan { .. } => "Input should be less than {lt}", Self::LessThanEqual { .. } => "Input should be less than or equal to {le}", Self::MultipleOf { .. } => "Input should be a multiple of {multiple_of}", Self::FiniteNumber { .. } => "Input should be a finite number", Self::TooShort { .. } => { "{field_type} should have at least {min_length} item{expected_plural} after validation, not {actual_length}" } Self::TooLong { .. } => { "{field_type} should have at most {max_length} item{expected_plural} after validation, not {actual_length}" } Self::IterableType { .. } => "Input should be iterable", Self::IterationError { .. } => "Error iterating over object, error: {error}", Self::StringType { .. } => "Input should be a valid string", Self::StringSubType { .. } => "Input should be a string, not an instance of a subclass of str", Self::StringUnicode { .. } => { "Input should be a valid string, unable to parse raw data as a unicode string" } Self::StringTooShort { .. } => "String should have at least {min_length} character{expected_plural}", Self::StringTooLong { .. } => "String should have at most {max_length} character{expected_plural}", Self::StringPatternMismatch { .. } => "String should match pattern '{pattern}'", Self::StringNotAscii { .. } => "String should contain only ASCII characters", Self::Enum { .. } => "Input should be {expected}", Self::DictType { .. } => "Input should be a valid dictionary", Self::MappingType { .. } => "Input should be a valid mapping, error: {error}", Self::ListType { .. } => "Input should be a valid list", Self::TupleType { .. } => "Input should be a valid tuple", Self::SetType { .. } => "Input should be a valid set", Self::SetItemNotHashable { .. } => "Set items should be hashable", Self::BoolType { .. } => "Input should be a valid boolean", Self::BoolParsing { .. } => "Input should be a valid boolean, unable to interpret input", Self::IntType { .. } => "Input should be a valid integer", Self::IntParsing { .. } => "Input should be a valid integer, unable to parse string as an integer", Self::IntFromFloat { .. } => "Input should be a valid integer, got a number with a fractional part", Self::IntParsingSize { .. } => "Unable to parse input string as an integer, exceeded maximum size", Self::FloatType { .. } => "Input should be a valid number", Self::FloatParsing { .. } => "Input should be a valid number, unable to parse string as a number", Self::BytesType { .. } => "Input should be a valid bytes", Self::BytesTooShort { .. } => "Data should have at least {min_length} byte{expected_plural}", Self::BytesTooLong { .. } => "Data should have at most {max_length} byte{expected_plural}", Self::BytesInvalidEncoding { .. } => "Data should be valid {encoding}: {encoding_error}", Self::ValueError { .. } => "Value error, {error}", Self::AssertionError { .. } => "Assertion failed, {error}", Self::CustomError { .. } => "", // custom errors are handled separately Self::LiteralError { .. } => "Input should be {expected}", Self::MissingSentinelError { .. } => "Input should be the 'MISSING' sentinel", Self::DateType { .. } => "Input should be a valid date", Self::DateParsing { .. } => "Input should be a valid date in the format YYYY-MM-DD, {error}", Self::DateFromDatetimeParsing { .. } => "Input should be a valid date or datetime, {error}", Self::DateFromDatetimeInexact { .. } => { "Datetimes provided to dates should have zero time - e.g. be exact dates" } Self::DatePast { .. } => "Date should be in the past", Self::DateFuture { .. } => "Date should be in the future", Self::TimeType { .. } => "Input should be a valid time", Self::TimeParsing { .. } => "Input should be in a valid time format, {error}", Self::DatetimeType { .. } => "Input should be a valid datetime", Self::DatetimeParsing { .. } => "Input should be a valid datetime, {error}", Self::DatetimeObjectInvalid { .. } => "Invalid datetime object, got {error}", Self::DatetimeFromDateParsing { .. } => "Input should be a valid datetime or date, {error}", Self::DatetimePast { .. } => "Input should be in the past", Self::DatetimeFuture { .. } => "Input should be in the future", Self::TimezoneNaive { .. } => "Input should not have timezone info", Self::TimezoneAware { .. } => "Input should have timezone info", Self::TimezoneOffset { .. } => "Timezone offset of {tz_expected} required, got {tz_actual}", Self::TimeDeltaType { .. } => "Input should be a valid timedelta", Self::TimeDeltaParsing { .. } => "Input should be a valid timedelta, {error}", Self::FrozenSetType { .. } => "Input should be a valid frozenset", Self::IsInstanceOf { .. } => "Input should be an instance of {class}", Self::IsSubclassOf { .. } => "Input should be a subclass of {class}", Self::CallableType { .. } => "Input should be callable", Self::UnionTagInvalid { .. } => { "Input tag '{tag}' found using {discriminator} does not match any of the expected tags: {expected_tags}" } Self::UnionTagNotFound { .. } => "Unable to extract tag using discriminator {discriminator}", Self::ArgumentsType { .. } => "Arguments must be a tuple, list or a dictionary", Self::MissingArgument { .. } => "Missing required argument", Self::UnexpectedKeywordArgument { .. } => "Unexpected keyword argument", Self::MissingKeywordOnlyArgument { .. } => "Missing required keyword only argument", Self::UnexpectedPositionalArgument { .. } => "Unexpected positional argument", Self::MissingPositionalOnlyArgument { .. } => "Missing required positional only argument", Self::MultipleArgumentValues { .. } => "Got multiple values for argument", Self::UrlType { .. } => "URL input should be a string or URL", Self::UrlParsing { .. } => "Input should be a valid URL, {error}", Self::UrlSyntaxViolation { .. } => "Input violated strict URL syntax rules, {error}", Self::UrlTooLong { .. } => "URL should have at most {max_length} character{expected_plural}", Self::UrlScheme { .. } => "URL scheme should be {expected_schemes}", Self::UuidType { .. } => "UUID input should be a string, bytes or UUID object", Self::UuidParsing { .. } => "Input should be a valid UUID, {error}", Self::UuidVersion { .. } => "UUID version {expected_version} expected", Self::DecimalType { .. } => "Decimal input should be an integer, float, string or Decimal object", Self::DecimalParsing { .. } => "Input should be a valid decimal", Self::DecimalMaxDigits { .. } => { "Decimal input should have no more than {max_digits} digit{expected_plural} in total" } Self::DecimalMaxPlaces { .. } => { "Decimal input should have no more than {decimal_places} decimal place{expected_plural}" } Self::DecimalWholeDigits { .. } => { "Decimal input should have no more than {whole_digits} digit{expected_plural} before the decimal point" } Self::ComplexType { .. } => { "Input should be a valid python complex object, a number, or a valid complex string following the rules at https://docs.python.org/3/library/functions.html#complex" } Self::ComplexStrParsing { .. } => { "Input should be a valid complex string following the rules at https://docs.python.org/3/library/functions.html#complex" } } } pub fn message_template_json(&self) -> &'static str { match self { Self::NoneRequired { .. } => "Input should be null", Self::ListType { .. } | Self::TupleType { .. } | Self::IterableType { .. } | Self::SetType { .. } | Self::FrozenSetType { .. } => "Input should be a valid array", Self::ModelType { .. } | Self::ModelAttributesType { .. } | Self::DictType { .. } | Self::DataclassType { .. } => "Input should be an object", Self::TimeDeltaType { .. } => "Input should be a valid duration", Self::TimeDeltaParsing { .. } => "Input should be a valid duration, {error}", Self::ArgumentsType { .. } => "Arguments must be an array or an object", _ => self.message_template_python(), } } pub fn valid_type(py: Python, error_type: &str) -> bool { let lookup = ERROR_TYPE_LOOKUP.get_or_init(py, Self::build_lookup); lookup.contains_key(error_type) } fn build_lookup() -> AHashMap { let mut lookup = AHashMap::new(); for error_type in Self::iter() { if !matches!(error_type, Self::CustomError { .. }) { lookup.insert(error_type.to_string(), error_type); } } lookup } pub fn type_string(&self) -> String { match self { Self::CustomError { error_type, .. } => error_type.clone(), _ => self.to_string(), } } pub fn render_message(&self, py: Python, input_type: InputType) -> PyResult { let tmpl = match input_type { InputType::Python => self.message_template_python(), _ => self.message_template_json(), }; match self { Self::NoSuchAttribute { attribute, .. } => render!(tmpl, attribute), Self::JsonInvalid { error, .. } | Self::GetAttributeError { error, .. } | Self::IterationError { error, .. } | Self::DatetimeObjectInvalid { error, .. } | Self::UrlParsing { error, .. } | Self::UuidParsing { error, .. } => render!(tmpl, error), Self::MappingType { error, .. } | Self::DateParsing { error, .. } | Self::DateFromDatetimeParsing { error, .. } | Self::TimeParsing { error, .. } | Self::DatetimeParsing { error, .. } | Self::DatetimeFromDateParsing { error, .. } | Self::TimeDeltaParsing { error, .. } | Self::UrlSyntaxViolation { error, .. } => render!(tmpl, error), Self::NeedsPythonObject { method_name, .. } => render!(tmpl, method_name), Self::ModelType { class_name, .. } | Self::DataclassType { class_name, .. } | Self::DataclassExactType { class_name, .. } => render!(tmpl, class_name), Self::GreaterThan { gt, .. } => to_string_render!(tmpl, gt), Self::GreaterThanEqual { ge, .. } => to_string_render!(tmpl, ge), Self::LessThan { lt, .. } => to_string_render!(tmpl, lt), Self::LessThanEqual { le, .. } => to_string_render!(tmpl, le), Self::MultipleOf { multiple_of, .. } => to_string_render!(tmpl, multiple_of), Self::TooShort { field_type, min_length, actual_length, .. } => { let expected_plural = plural_s(*min_length); to_string_render!(tmpl, field_type, min_length, actual_length, expected_plural,) } Self::TooLong { field_type, max_length, actual_length, .. } => { let expected_plural = plural_s(*max_length); let actual_length = actual_length.map_or(Cow::Borrowed("more"), |v| Cow::Owned(v.to_string())); to_string_render!(tmpl, field_type, max_length, actual_length, expected_plural,) } Self::StringTooShort { min_length, .. } | Self::BytesTooShort { min_length, .. } => { let expected_plural = plural_s(*min_length); to_string_render!(tmpl, min_length, expected_plural) } Self::StringTooLong { max_length, .. } | Self::BytesTooLong { max_length, .. } | Self::UrlTooLong { max_length, .. } => { let expected_plural = plural_s(*max_length); to_string_render!(tmpl, max_length, expected_plural) } Self::StringPatternMismatch { pattern, .. } => render!(tmpl, pattern), Self::Enum { expected, .. } => to_string_render!(tmpl, expected), Self::BytesInvalidEncoding { encoding, encoding_error, .. } => render!(tmpl, encoding, encoding_error), Self::ValueError { error, .. } => { let error = &error .as_ref() .map_or(Cow::Borrowed("None"), |v| Cow::Owned(v.bind(py).to_string())); render!(tmpl, error) } Self::AssertionError { error, .. } => { let error = &error .as_ref() .map_or(Cow::Borrowed("None"), |v| Cow::Owned(v.bind(py).to_string())); render!(tmpl, error) } Self::CustomError { message_template, context, .. } => PydanticCustomError::format_message(message_template, context.as_ref().map(|c| c.bind(py))), Self::LiteralError { expected, .. } => render!(tmpl, expected), Self::TimezoneOffset { tz_expected, tz_actual, .. } => to_string_render!(tmpl, tz_expected, tz_actual), Self::IsInstanceOf { class, .. } | Self::IsSubclassOf { class, .. } => render!(tmpl, class), Self::UnionTagInvalid { discriminator, tag, expected_tags, .. } => render!(tmpl, discriminator, tag, expected_tags), Self::UnionTagNotFound { discriminator, .. } => render!(tmpl, discriminator), Self::UrlScheme { expected_schemes, .. } => render!(tmpl, expected_schemes), Self::UuidVersion { expected_version, .. } => to_string_render!(tmpl, expected_version), Self::DecimalMaxDigits { max_digits, .. } => { let expected_plural = plural_s(*max_digits); to_string_render!(tmpl, max_digits, expected_plural) } Self::DecimalMaxPlaces { decimal_places, .. } => { let expected_plural = plural_s(*decimal_places); to_string_render!(tmpl, decimal_places, expected_plural) } Self::DecimalWholeDigits { whole_digits, .. } => { let expected_plural = plural_s(*whole_digits); to_string_render!(tmpl, whole_digits, expected_plural) } _ => Ok(tmpl.to_string()), } } pub fn py_dict(&self, py: Python) -> PyResult>> { let dict = PyDict::new(py); let custom_ctx_used = self.py_dict_update_ctx(py, &dict)?; if let Self::CustomError { .. } = self { if custom_ctx_used { // Custom error type and message are handled separately by the caller. // They are added to the root of the ErrorDetails. dict.del_item("error_type")?; dict.del_item("message_template")?; Ok(Some(dict.into())) } else { Ok(None) } } else if custom_ctx_used || !dict.is_empty() { Ok(Some(dict.into())) } else { Ok(None) } } } #[derive(Clone, Debug, IntoPyObject, IntoPyObjectRef)] pub enum Number { Int(i64), BigInt(BigInt), Float(f64), String(String), } impl Default for Number { fn default() -> Self { Self::Int(0) } } impl From for Number { fn from(f: f64) -> Self { Self::Float(f) } } impl From for Number { fn from(s: String) -> Self { Self::String(s) } } impl From for Number { fn from(i: Int) -> Self { match i { Int::I64(i) => Number::Int(i), Int::Big(b) => Number::BigInt(b), } } } impl FromPyObject<'_, '_> for Number { type Error = PyErr; #[allow(clippy::same_functions_in_if_condition)] // https://github.com/rust-lang/rust-clippy/issues/10928 fn extract(obj: Borrowed<'_, '_, PyAny>) -> PyResult { if let Ok(int) = obj.extract() { Ok(Number::Int(int)) } else if let Ok(float) = obj.extract() { Ok(Number::Float(float)) } else if let Ok(string) = obj.extract() { Ok(Number::String(string)) } else { py_err!(PyTypeError; "Expected int or float or String, got {}", obj.get_type()) } } } impl fmt::Display for Number { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Float(s) => write!(f, "{s}"), Self::Int(i) => write!(f, "{i}"), Self::BigInt(i) => write!(f, "{i}"), Self::String(s) => write!(f, "{s}"), } } } pydantic-pydantic-ba0aa01/pydantic-core/src/errors/validation_exception.rs000066400000000000000000000555761517143232300272520ustar00rootroot00000000000000use std::borrow::Cow; use std::cell::RefCell; use std::fmt; use std::fmt::{Display, Write}; use std::str::from_utf8; use pyo3::exceptions::{PyKeyError, PyTypeError, PyValueError}; use pyo3::ffi::{self, c_str}; use pyo3::intern; use pyo3::prelude::*; use pyo3::sync::PyOnceLock; use pyo3::types::{PyDict, PyList, PyString, PyTuple, PyType}; use serde::ser::{Error, SerializeMap, SerializeSeq}; use serde::{Serialize, Serializer}; use serde_json::ser::PrettyFormatter; use crate::build_tools::py_schema_error_type; use crate::errors::LocItem; use crate::get_pydantic_version; use crate::input::InputType; use crate::serializers::{Extra, SerMode, SerializationConfig, SerializationState, WarningsMode}; use crate::tools::{SchemaDict, safe_repr, write_truncated_to_limited_bytes}; use super::line_error::ValLineError; use super::location::Location; use super::types::ErrorType; use super::value_exception::PydanticCustomError; use super::{InputValue, ValError}; #[pyclass(extends=PyValueError, module="pydantic_core._pydantic_core", subclass, skip_from_py_object, frozen)] #[derive(Clone)] #[cfg_attr(debug_assertions, derive(Debug))] pub struct ValidationError { line_errors: Vec, title: Py, input_type: InputType, hide_input: bool, } impl ValidationError { pub fn new(line_errors: Vec, title: Py, input_type: InputType, hide_input: bool) -> Self { Self { line_errors, title, input_type, hide_input, } } pub fn from_val_error( py: Python, title: Py, input_type: InputType, error: ValError, outer_location: Option, hide_input: bool, validation_error_cause: bool, ) -> PyErr { match error { ValError::LineErrors(raw_errors) => { let line_errors = match outer_location { Some(outer_location) => raw_errors .into_iter() .map(|e| PyLineError::from_val_line_error(py, e.with_outer_location(outer_location.clone()))) .collect(), None => raw_errors .into_iter() .map(|e| PyLineError::from_val_line_error(py, e)) .collect(), }; let line_errors = match line_errors { Ok(errors) => errors, Err(err) => return err, }; let validation_error = Self::new(line_errors, title, input_type, hide_input); match Bound::new(py, validation_error) { Ok(err) => { // Will return an import error if the backport was needed and not installed: if validation_error_cause && let Some(cause_problem) = ValidationError::maybe_add_cause(err.borrow(), py) { return cause_problem; } PyErr::from_value(err.into_any()) } Err(err) => err, } } ValError::InternalErr(err) => err, ValError::Omit => Self::omit_error(), ValError::UseDefault => Self::use_default_error(), } } pub fn display(&self, py: Python, prefix_override: Option<&'static str>, hide_input: bool) -> String { let url_prefix = get_url_prefix(py, include_url_env(py)); let line_errors = pretty_py_line_errors(py, self.input_type, self.line_errors.iter(), url_prefix, hide_input); if let Some(prefix) = prefix_override { format!("{prefix}\n{line_errors}") } else { let count = self.line_errors.len(); let plural = if count == 1 { "" } else { "s" }; let title: &str = self.title.extract(py).unwrap(); format!("{count} validation error{plural} for {title}\n{line_errors}") } } pub fn omit_error() -> PyErr { py_schema_error_type!("Uncaught Omit error, please check your usage of `default` validators.") } pub fn use_default_error() -> PyErr { py_schema_error_type!( "Uncaught `PydanticUseDefault` exception: the error was raised in a field validator and no default value is available for that field." ) } fn maybe_add_cause(self_: PyRef<'_, Self>, py: Python) -> Option { let mut user_py_errs = vec![]; for line_error in &self_.line_errors { if let ErrorType::AssertionError { error: Some(err), context: _, } | ErrorType::ValueError { error: Some(err), context: _, } = &line_error.error_type { let note = if let Location::Empty = &line_error.location { Cow::Borrowed("Pydantic: cause of loc: root") } else { Cow::Owned(format!( "Pydantic: cause of loc: {}", // Location formats with a newline at the end, hence the trim() line_error.location.to_string().trim() )) }; // Notes only support 3.11 upwards: #[cfg(Py_3_11)] { // Add the location context as a note, no direct c api for this, // fine performance wise, add_note() goes directly to C: "(PyCFunction)BaseException_add_note": // https://github.com/python/cpython/blob/main/Objects/exceptions.c if err.call_method1(py, "add_note", (format!("\n{note}"),)).is_ok() { user_py_errs.push(err.clone_ref(py)); } } // Pre 3.11 notes support, use a UserWarning exception instead: #[cfg(not(Py_3_11))] { use pyo3::exceptions::PyUserWarning; let wrapped = PyUserWarning::new_err((note,)); wrapped.set_cause(py, Some(PyErr::from_value(err.clone_ref(py).into_bound(py)))); user_py_errs.push(wrapped); } } } // Only add the cause if there are actually python user exceptions to show: if !user_py_errs.is_empty() { let title = "Pydantic User Code Exceptions"; // Native ExceptionGroup(s) only supported 3.11 and later: #[cfg(Py_3_11)] let cause = { use pyo3::exceptions::PyBaseExceptionGroup; Some(PyBaseExceptionGroup::new_err((title, user_py_errs)).into_value(py)) }; // Pre 3.11 ExceptionGroup support, use the python backport instead: // If something's gone wrong with the backport, just don't add the cause: #[cfg(not(Py_3_11))] let cause = { use pyo3::exceptions::PyImportError; match py.import("exceptiongroup") { Ok(py_mod) => match py_mod.getattr("ExceptionGroup") { Ok(group_cls) => group_cls.call1((title, user_py_errs)).ok(), Err(_) => None, }, Err(_) => { return Some(PyImportError::new_err( "validation_error_cause flag requires the exceptiongroup module backport to be installed when used on Python <3.11.", )); } } }; // Set the cause to the ValidationError: if let Some(cause) = cause { unsafe { // PyException_SetCause _steals_ a reference to cause, so must use .into_ptr() ffi::PyException_SetCause(self_.as_ptr(), cause.into_ptr()); } } } None } } static URL_ENV_VAR: PyOnceLock = PyOnceLock::new(); fn include_url_env(py: Python) -> bool { *URL_ENV_VAR.get_or_init(py, || { // Check the legacy env var first. // Using `var_os` here instead of `var` because we don't care about // the value (or whether we're able to decode it as UTF-8), just // whether it exists (and if it does, whether it's non-empty). match std::env::var_os("PYDANTIC_ERRORS_OMIT_URL") { Some(val) => { // We don't care whether warning succeeded or not, hence the assignment let _ = PyErr::warn( py, &py.get_type::(), c_str!("PYDANTIC_ERRORS_OMIT_URL is deprecated, use PYDANTIC_ERRORS_INCLUDE_URL instead"), 1, ); // If OMIT_URL exists but is empty, we include the URL: val.is_empty() } // If the legacy env var doesn't exist, check the documented one: None => match std::env::var("PYDANTIC_ERRORS_INCLUDE_URL") { Ok(val) => val == "1" || val.to_lowercase() == "true", Err(_) => true, }, } }) } static URL_PREFIX: PyOnceLock = PyOnceLock::new(); fn get_formated_url(py: Python) -> &'static str { let pydantic_version = match get_pydantic_version(py) { // include major and minor version only Some(value) => value.split('.').collect::>()[..2].join("."), None => "latest".to_string(), }; URL_PREFIX.get_or_init(py, || format!("https://errors.pydantic.dev/{pydantic_version}/v/")) } fn get_url_prefix(py: Python<'_>, include_url: bool) -> Option<&str> { if include_url { Some(get_formated_url(py)) } else { None } } // used to convert a validation error back to ValError for wrap functions impl ValidationError { pub(crate) fn into_val_error(self) -> ValError { self.line_errors.into_iter().map(Into::into).collect::>().into() } } #[pymethods] impl ValidationError { #[new] #[pyo3(signature = (title, line_errors, input_type="python", hide_input=false))] fn py_new(title: Py, line_errors: Vec, input_type: &str, hide_input: bool) -> PyResult { Ok(Self { line_errors, title, input_type: InputType::try_from(input_type)?, hide_input, }) } #[classmethod] #[pyo3(signature = (title, line_errors, input_type="python", hide_input=false))] fn from_exception_data<'py>( cls: &Bound<'py, PyType>, title: Py, line_errors: Bound<'_, PyList>, input_type: &str, hide_input: bool, ) -> PyResult> { cls.call1(( title, line_errors .iter() .map(|error| PyLineError::try_from(&error)) .collect::>>()?, InputType::try_from(input_type)?, hide_input, )) } #[getter] fn title(&self, py: Python) -> Py { self.title.clone_ref(py) } pub fn error_count(&self) -> usize { self.line_errors.len() } #[pyo3(signature = (*, include_url = true, include_context = true, include_input = true))] pub fn errors( &self, py: Python, include_url: bool, include_context: bool, include_input: bool, ) -> PyResult> { let url_prefix = get_url_prefix(py, include_url); let mut iteration_error = None; let list = PyList::new( py, // PyList::new takes ExactSizeIterator, so if an error occurs during iteration we // fill the list with None before returning the error; the list will then be thrown // away safely. self.line_errors.iter().map(|e| -> Py { if iteration_error.is_some() { return py.None(); } e.as_dict(py, url_prefix, include_context, self.input_type, include_input) .map_or_else( |err| { iteration_error = Some(err); py.None() }, Into::into, ) }), )?; if let Some(err) = iteration_error { Err(err) } else { Ok(list.unbind()) } } #[pyo3(signature = (*, indent = None, include_url = true, include_context = true, include_input = true))] pub fn json<'py>( &self, py: Python<'py>, indent: Option, include_url: bool, include_context: bool, include_input: bool, ) -> PyResult> { let config = SerializationConfig::default(); let extra = Extra::new( py, SerMode::Json, None, false, false, false, false, false, true, None, false, None, None, ); let mut state = SerializationState::new(config, WarningsMode::None, None, None, extra)?; let mut serializer = ValidationErrorSerializer { py, line_errors: &self.line_errors, url_prefix: get_url_prefix(py, include_url), include_context, include_input, state: &mut state, input_type: &self.input_type, }; let writer: Vec = Vec::with_capacity(self.line_errors.len() * 200); let bytes = match indent { Some(indent) => { let indent = vec![b' '; indent]; let formatter = PrettyFormatter::with_indent(&indent); let mut ser = crate::serializers::ser::PythonSerializer::with_formatter(writer, formatter); serializer.serialize(&mut ser).map_err(json_py_err)?; ser.into_inner() } None => { let mut ser = crate::serializers::ser::PythonSerializer::new(writer); serializer.serialize(&mut ser).map_err(json_py_err)?; ser.into_inner() } }; let s = from_utf8(&bytes).map_err(json_py_err)?; Ok(PyString::new(py, s)) } fn __repr__(&self, py: Python) -> String { self.display(py, None, self.hide_input) } fn __str__(&self, py: Python) -> String { self.__repr__(py) } fn __reduce__<'py>(slf: &Bound<'py, Self>) -> PyResult<(Bound<'py, PyAny>, Bound<'py, PyTuple>)> { let py = slf.py(); let callable = slf.getattr("from_exception_data")?; let borrow = slf.try_borrow()?; let args = ( &borrow.title, borrow.errors(py, include_url_env(py), true, true)?, borrow.input_type, borrow.hide_input, ) .into_pyobject(py)?; Ok((callable, args)) } } pub fn pretty_py_line_errors<'a>( py: Python, input_type: InputType, line_errors_iter: impl Iterator, url_prefix: Option<&str>, hide_input: bool, ) -> String { line_errors_iter .map(|i| i.pretty(py, input_type, url_prefix, hide_input)) .collect::, _>>() .unwrap_or_else(|err| vec![format!("[error formatting line errors: {err}]")]) .join("\n") } /// `PyLineError` are the public version of `ValLineError`, as help and used in `ValidationError`s #[pyclass(from_py_object)] #[derive(Clone)] #[cfg_attr(debug_assertions, derive(Debug))] pub struct PyLineError { error_type: ErrorType, location: Location, input_value: Py, } impl From for ValLineError { /// Used to extract line errors from a validation error for wrap functions fn from(other: PyLineError) -> ValLineError { ValLineError { error_type: other.error_type, location: other.location, input_value: InputValue::Python(other.input_value), } } } impl TryFrom<&Bound<'_, PyAny>> for PyLineError { type Error = PyErr; fn try_from(value: &Bound<'_, PyAny>) -> PyResult { let dict = value.cast::()?; let py = value.py(); let type_raw = dict .get_item(intern!(py, "type"))? .ok_or_else(|| PyKeyError::new_err("type"))?; let error_type = if let Ok(type_str) = type_raw.cast::() { let context: Option> = dict.get_as(intern!(py, "ctx"))?; ErrorType::new(py, type_str.to_str()?, context)? } else if let Ok(custom_error) = type_raw.cast::() { ErrorType::new_custom_error(py, custom_error.get().clone()) } else { return Err(PyTypeError::new_err( "`type` should be a `str` or `PydanticCustomError`", )); }; let location = Location::try_from(dict.get_item("loc")?.as_ref())?; let input_value = match dict.get_item("input")? { Some(i) => i.unbind(), None => py.None(), }; Ok(Self { error_type, location, input_value, }) } } impl PyLineError { pub fn from_val_line_error(py: Python, error: ValLineError) -> PyResult { Ok(Self { error_type: error.error_type, location: error.location, input_value: error.input_value.into_pyobject(py)?.unbind(), }) } fn get_error_url(&self, url_prefix: &str) -> String { format!("{url_prefix}{}", self.error_type.type_string()) } pub fn as_dict<'py>( &self, py: Python<'py>, url_prefix: Option<&str>, include_context: bool, input_type: InputType, include_input: bool, ) -> PyResult> { let dict = PyDict::new(py); dict.set_item("type", self.error_type.type_string())?; dict.set_item("loc", &self.location)?; dict.set_item("msg", self.error_type.render_message(py, input_type)?)?; if include_input { dict.set_item("input", &self.input_value)?; } if include_context && let Some(context) = self.error_type.py_dict(py)? { dict.set_item("ctx", context)?; } if let Some(url_prefix) = url_prefix // Don't add URLs for custom errors && !matches!(self.error_type, ErrorType::CustomError { .. }) { dict.set_item("url", self.get_error_url(url_prefix))?; } Ok(dict) } fn pretty( &self, py: Python, input_type: InputType, url_prefix: Option<&str>, hide_input: bool, ) -> Result { let mut output = String::with_capacity(200); write!(output, "{}", self.location)?; let message = match self.error_type.render_message(py, input_type) { Ok(message) => message, Err(err) => format!("(error rendering message: {err})"), }; write!(output, " {message} [type={}", self.error_type.type_string())?; // special case: don't show input for DefaultFactoryNotCalled errors - there is no valid input if !hide_input && !matches!(self.error_type, ErrorType::DefaultFactoryNotCalled { .. }) { let input_value = self.input_value.bind(py); let input_str = safe_repr(input_value); write!(output, ", input_value=")?; write_truncated_to_limited_bytes(&mut output, &input_str.to_string(), 50)?; if let Ok(type_) = input_value.get_type().qualname() { write!(output, ", input_type={type_}")?; } } output.push(']'); if let Some(url_prefix) = url_prefix // Don't display URLs for custom errors && !matches!(self.error_type, ErrorType::CustomError { .. }) { write!( output, "\n For further information visit {}", self.get_error_url(url_prefix) )?; } Ok(output) } } pub(super) fn json_py_err(error: impl Display) -> PyErr { PyValueError::new_err(format!("Error serializing ValidationError to JSON: {error}")) } pub(super) fn py_err_json(error: PyErr) -> S::Error where S: Serializer, { S::Error::custom(error.to_string()) } struct ValidationErrorSerializer<'slf, 'py> { py: Python<'py>, line_errors: &'py [PyLineError], url_prefix: Option<&'py str>, include_context: bool, include_input: bool, state: &'slf mut SerializationState<'py>, input_type: &'py InputType, } impl ValidationErrorSerializer<'_, '_> { fn serialize(&mut self, serializer: S) -> Result where S: Serializer, { let mut seq = serializer.serialize_seq(Some(self.line_errors.len()))?; for line_error in self.line_errors { let line_s = PyLineErrorSerializer { py: self.py, line_error, url_prefix: self.url_prefix, include_context: self.include_context, include_input: self.include_input, state: RefCell::new(self.state), input_type: self.input_type, }; seq.serialize_element(&line_s)?; } seq.end() } } struct PyLineErrorSerializer<'slf, 'py> { py: Python<'py>, line_error: &'py PyLineError, url_prefix: Option<&'py str>, include_context: bool, include_input: bool, state: RefCell<&'slf mut SerializationState<'py>>, input_type: &'py InputType, } impl Serialize for PyLineErrorSerializer<'_, '_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let py = self.py; let size = 3 + [self.url_prefix.is_some(), self.include_context, self.include_input] .into_iter() .filter(|b| *b) .count(); let mut map = serializer.serialize_map(Some(size))?; let mut state = self.state.borrow_mut(); map.serialize_entry("type", &self.line_error.error_type.type_string())?; map.serialize_entry("loc", &self.line_error.location)?; let msg = self .line_error .error_type .render_message(py, *self.input_type) .map_err(py_err_json::)?; map.serialize_entry("msg", &msg)?; if self.include_input { map.serialize_entry("input", &state.serialize_infer(self.line_error.input_value.bind(py)))?; } if self.include_context && let Some(context) = self.line_error.error_type.py_dict(py).map_err(py_err_json::)? { map.serialize_entry("ctx", &state.serialize_infer(context.bind(py)))?; } if let Some(url_prefix) = self.url_prefix { map.serialize_entry("url", &self.line_error.get_error_url(url_prefix))?; } map.end() } } pydantic-pydantic-ba0aa01/pydantic-core/src/errors/value_exception.rs000066400000000000000000000125341517143232300262170ustar00rootroot00000000000000use pyo3::exceptions::{PyException, PyValueError}; use pyo3::prelude::*; use pyo3::types::{PyDict, PyString}; use crate::input::InputType; use super::line_error::ToErrorValue; use super::{ErrorType, ValError}; #[pyclass(extends=PyException, module="pydantic_core._pydantic_core", skip_from_py_object)] #[derive(Debug, Clone)] pub struct PydanticOmit {} impl PydanticOmit { pub(crate) fn new_err() -> PyErr { PyErr::new::(()) } } #[pymethods] impl PydanticOmit { #[new] pub fn py_new() -> Self { Self {} } fn __str__(&self) -> &'static str { self.__repr__() } fn __repr__(&self) -> &'static str { "PydanticOmit()" } } #[pyclass(extends=PyException, module="pydantic_core._pydantic_core", skip_from_py_object)] #[derive(Debug, Clone)] pub struct PydanticUseDefault {} #[pymethods] impl PydanticUseDefault { #[new] pub fn py_new() -> Self { Self {} } fn __str__(&self) -> &'static str { self.__repr__() } fn __repr__(&self) -> &'static str { "PydanticUseDefault()" } } #[pyclass(extends=PyValueError, module="pydantic_core._pydantic_core", subclass, frozen, skip_from_py_object)] #[derive(Debug, Clone, Default)] pub struct PydanticCustomError { error_type: String, message_template: String, context: Option>, } #[pymethods] impl PydanticCustomError { #[new] #[pyo3(signature = (error_type, message_template, context = None, /))] pub fn py_new(error_type: String, message_template: String, context: Option>) -> Self { Self { error_type, message_template, context: context.map(Bound::unbind), } } #[getter(r#type)] pub fn error_type(&self) -> &str { &self.error_type } #[getter] pub fn message_template(&self) -> &str { &self.message_template } #[getter] pub fn context(&self, py: Python) -> Option> { self.context.as_ref().map(|c| c.clone_ref(py)) } pub fn message(&self, py: Python) -> PyResult { Self::format_message(&self.message_template, self.context.as_ref().map(|c| c.bind(py))) } fn __str__(&self, py: Python) -> PyResult { self.message(py) } fn __repr__(&self, py: Python) -> PyResult { let msg = self.message(py)?; match self.context.as_ref() { Some(ctx) => Ok(format!("{msg} [type={}, context={}]", self.error_type, ctx.bind(py))), None => Ok(format!("{msg} [type={}, context=None]", self.error_type)), } } } impl PydanticCustomError { pub fn into_val_error(self, input: impl ToErrorValue) -> ValError { let error_type = ErrorType::CustomError { error_type: self.error_type, message_template: self.message_template, context: self.context, }; ValError::new(error_type, input) } pub fn format_message(message_template: &str, context: Option<&Bound<'_, PyDict>>) -> PyResult { let mut message = message_template.to_string(); if let Some(ctx) = context { for (key, value) in ctx.iter() { let key = key.cast::()?; if let Ok(py_str) = value.cast::() { message = message.replace(&format!("{{{}}}", key.to_str()?), py_str.to_str()?); } else if let Ok(value_int) = value.extract::() { message = message.replace(&format!("{{{}}}", key.to_str()?), &value_int.to_string()); } else { // fallback for anything else just in case message = message.replace(&format!("{{{}}}", key.to_str()?), &value.to_string()); } } } Ok(message) } } #[pyclass(extends=PyValueError, module="pydantic_core._pydantic_core", skip_from_py_object, frozen)] #[derive(Debug, Clone)] pub struct PydanticKnownError { error_type: ErrorType, } #[pymethods] impl PydanticKnownError { #[new] #[pyo3(signature = (error_type, context=None, /))] pub fn py_new(py: Python, error_type: &str, context: Option>) -> PyResult { let error_type = ErrorType::new(py, error_type, context)?; Ok(Self { error_type }) } #[getter(r#type)] pub fn error_type(&self) -> String { self.error_type.to_string() } #[getter] pub fn message_template(&self) -> &'static str { self.error_type.message_template_python() } #[getter] pub fn context(&self, py: Python) -> PyResult>> { self.error_type.py_dict(py) } pub fn message(&self, py: Python) -> PyResult { self.error_type.render_message(py, InputType::Python) } fn __str__(&self, py: Python) -> PyResult { self.message(py) } fn __repr__(&self, py: Python) -> PyResult { let msg = self.message(py)?; match self.context(py)?.as_ref() { Some(ctx) => Ok(format!("{msg} [type={}, context={}]", self.error_type(), ctx.bind(py))), None => Ok(format!("{msg} [type={}, context=None]", self.error_type())), } } } impl PydanticKnownError { pub fn into_val_error(self, input: impl ToErrorValue) -> ValError { ValError::new(self.error_type, input) } } pydantic-pydantic-ba0aa01/pydantic-core/src/input/000077500000000000000000000000001517143232300222755ustar00rootroot00000000000000pydantic-pydantic-ba0aa01/pydantic-core/src/input/datetime.rs000066400000000000000000000662421517143232300244510ustar00rootroot00000000000000use pyo3::intern; use pyo3::prelude::*; use pyo3::IntoPyObjectExt; use pyo3::exceptions::PyValueError; use pyo3::pyclass::CompareOp; use pyo3::types::PyDateAccess; use pyo3::types::PyTimeAccess; use pyo3::types::PyTuple; use pyo3::types::PyTzInfoAccess; use pyo3::types::{PyDate, PyDateTime, PyDelta, PyDeltaAccess, PyDict, PyTime, PyTzInfo}; use speedate::DateConfig; use speedate::{ Date, DateTime, DateTimeConfig, Duration, MicrosecondsPrecisionOverflowBehavior, ParseError, Time, TimeConfig, }; use std::borrow::Cow; use std::collections::hash_map::DefaultHasher; use std::fmt::Write; use std::hash::Hash; use std::hash::Hasher; use strum::EnumMessage; use super::Input; use crate::errors::ToErrorValue; use crate::errors::{ErrorType, ValError, ValResult}; use crate::tools::py_err; use crate::validators::TemporalUnitMode; #[cfg_attr(debug_assertions, derive(Debug))] pub enum EitherDate<'py> { Raw(Date), Py(Bound<'py, PyDate>), } impl From for EitherDate<'_> { fn from(date: Date) -> Self { Self::Raw(date) } } impl<'py> From> for EitherDate<'py> { fn from(date: Bound<'py, PyDate>) -> Self { Self::Py(date) } } pub fn pydate_as_date(py_date: &Bound<'_, PyAny>) -> PyResult { if let Ok(py_date) = py_date.cast_exact::() { return pydateaccess_as_date(py_date); } py_any_date_as_date(py_date) } /// Fast path for reading date information from `datetime.date` and `datetime.datetime` objects #[inline] fn pydateaccess_as_date(py_date: &impl PyDateAccess) -> PyResult { Ok(Date { year: py_date.get_year().try_into()?, month: py_date.get_month(), day: py_date.get_day(), }) } /// Slow path for reading date information from subclasses of the builtin datetime types #[cold] fn py_any_date_as_date(py_date: &Bound<'_, PyAny>) -> PyResult { let py = py_date.py(); Ok(Date { year: py_date.getattr(intern!(py, "year"))?.extract()?, month: py_date.getattr(intern!(py, "month"))?.extract()?, day: py_date.getattr(intern!(py, "day"))?.extract()?, }) } impl<'py> EitherDate<'py> { pub fn try_into_py(self, py: Python<'py>, input: &(impl Input<'py> + ?Sized)) -> ValResult> { match self { Self::Raw(date) => { if date.year == 0 { return Err(ValError::new( ErrorType::DateParsing { error: Cow::Borrowed("year 0 is out of range"), context: None, }, input, )); } let py_date = PyDate::new(py, date.year.into(), date.month, date.day)?; Ok(py_date.into()) } Self::Py(py_date) => Ok(py_date.into()), } } pub fn as_raw(&self) -> PyResult { match self { Self::Raw(date) => Ok(*date), Self::Py(py_date) => pydate_as_date(py_date), } } } #[cfg_attr(debug_assertions, derive(Debug))] pub enum EitherTime<'py> { Raw(Time), Py(Bound<'py, PyTime>), } impl From

pydantic-core unit tests

loading...