mirror of
https://github.com/kennethreitz/pydantic.git
synced 2026-06-05 06:46:17 +00:00
Remove Cython & Move to pyproject.toml (#4473)
* Remove Cython * fix CI * fix coverage * fix tests * switching to pypyroject.toml * pre-commit all and use pre-commit for linting * no mypy tests on macos and windows on ci, use flake8-pyproject * fix docs and tests CI * check build is working * drop pytest-cov * window and macos ci with 3.11, reduce filtering * use pip-tools to pin all dependencies * fix docs and fastapi tests * fix test deps for 3.7 * no cache on tests job * revert fastapi changes, fix coverage * fix mypy coverage * test with older mypy * dotenv not required for mypy tests * split testing requirements std and extra * typo * @PrettyWood comments * correct branch name * mypy python_version and pr template
This commit is contained in:
@@ -13,7 +13,7 @@ body:
|
||||
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
|
||||
@@ -23,7 +23,7 @@ body:
|
||||
- label: I have read and followed [the docs](https://pydantic-docs.helpmanual.io) and still think this is a bug
|
||||
required: true
|
||||
- label: >
|
||||
I am confident that the issue is with pydantic
|
||||
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
|
||||
@@ -60,7 +60,7 @@ body:
|
||||
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
|
||||
|
||||
@@ -13,7 +13,7 @@ body:
|
||||
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
|
||||
@@ -27,7 +27,7 @@ body:
|
||||
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
|
||||
|
||||
@@ -1,23 +1,14 @@
|
||||
<!-- Thank you for your contribution! -->
|
||||
<!-- Unless your change is trivial, please create an issue to discuss the change before creating a PR -->
|
||||
<!-- See https://pydantic-docs.helpmanual.io/contributing/ for help on Contributing -->
|
||||
<!-- PLEASE DO **NOT** put issue ids in the PR title! Instead, add a descriptive title and put ids in the body -->
|
||||
# WARNING!!!
|
||||
|
||||
## Change Summary
|
||||
We're currently in the process of rewriting pydantic in preparation for V2, see
|
||||
https://pydantic-docs.helpmanual.io/blog/pydantic-v2/.
|
||||
|
||||
<!-- Please give a short summary of the changes. -->
|
||||
As a result, much of the codebase will change significantly over the coming months.
|
||||
|
||||
## Related issue number
|
||||
To avoid wasting your time, please only create Pull Requests if you've got explicit approval by a maintainer.
|
||||
|
||||
<!-- Are there any issues opened that will be resolved by merging this change? -->
|
||||
<!-- WARNING: please use "fix #123" style references so the issue is closed when this PR is merged. -->
|
||||
Otherwise, your pull requests may be closed without review.
|
||||
|
||||
## Checklist
|
||||
Thank you for your interest in pydantic, and your patience. :pray:
|
||||
|
||||
* [ ] Unit tests for the changes exist
|
||||
* [ ] Tests pass on CI and coverage remains at 100%
|
||||
* [ ] Documentation reflects the changes where applicable
|
||||
* [ ] `changes/<pull request or issue id>-<github username>.md` file added describing change
|
||||
(see [changes/README.md](https://github.com/pydantic/pydantic/blob/main/changes/README.md) for details.
|
||||
You can [skip this check](https://github.com/pydantic/hooky#change-file-checks) if the change does not need a change file.)
|
||||
* [ ] My PR is ready to review, **please add a comment including the phrase "please review" to assign reviewers**
|
||||
**Note:** if you're making a pull request to fix pydantic v1.10, please make it against the `1.10.X-fixes` branch.
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
version: 2
|
||||
|
||||
updates:
|
||||
- package-ecosystem: pip
|
||||
directory: /
|
||||
schedule:
|
||||
interval: monthly
|
||||
|
||||
- package-ecosystem: github-actions
|
||||
directory: /
|
||||
schedule:
|
||||
|
||||
+70
-202
@@ -30,29 +30,19 @@ jobs:
|
||||
lint
|
||||
${{ runner.os }}
|
||||
${{ env.pythonLocation }}
|
||||
${{ hashFiles('tests/requirements-linting.txt') }}
|
||||
${{ hashFiles('requirements/linting.txt') }}
|
||||
|
||||
- name: install
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
make install-linting
|
||||
pip freeze
|
||||
run: pip install -r requirements/linting.txt
|
||||
|
||||
- name: lint
|
||||
run: make lint
|
||||
|
||||
- name: pyupgrade
|
||||
run: make pyupgrade
|
||||
|
||||
- name: mypy
|
||||
run: make mypy
|
||||
- uses: pre-commit/action@v3.0.0
|
||||
with:
|
||||
extra_args: --all-files
|
||||
|
||||
- name: make history
|
||||
run: python3 ./changes/make_history.py
|
||||
|
||||
- name: check dist
|
||||
run: make check-dist
|
||||
|
||||
- name: install node for pyright
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
@@ -80,13 +70,12 @@ jobs:
|
||||
docs-build
|
||||
${{ runner.os }}
|
||||
${{ env.pythonLocation }}
|
||||
${{ hashFiles('setup.py') }}
|
||||
${{ hashFiles('requirements.txt') }}
|
||||
${{ hashFiles('docs/requirements.txt') }}
|
||||
${{ hashFiles('requirements/pyproject-all.txt') }}
|
||||
${{ hashFiles('requirements/docs.txt') }}
|
||||
|
||||
- name: install
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: make install-docs
|
||||
run: pip install -r requirements/pyproject-all.txt -r requirements/docs.txt .
|
||||
|
||||
- name: build site
|
||||
run: make docs
|
||||
@@ -97,75 +86,17 @@ jobs:
|
||||
name: docs
|
||||
path: site
|
||||
|
||||
test-linux-compiled:
|
||||
name: test py${{ matrix.python-version }} on linux compiled
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: ['3.7', '3.8', '3.9', '3.10', '3.11.0-rc.1']
|
||||
env:
|
||||
PYTHON: ${{ matrix.python-version }}
|
||||
OS: ubuntu
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: set up python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- uses: actions/cache@v3
|
||||
id: cache
|
||||
with:
|
||||
path: ${{ env.pythonLocation }}
|
||||
key: >
|
||||
test-linux-compiled
|
||||
${{ runner.os }}
|
||||
${{ env.pythonLocation }}
|
||||
${{ hashFiles('setup.py') }}
|
||||
${{ hashFiles('requirements.txt') }}
|
||||
${{ hashFiles('tests/requirements-testing.txt') }}
|
||||
|
||||
- name: install
|
||||
run: make install-testing
|
||||
|
||||
- name: compile
|
||||
run: |
|
||||
make build-trace
|
||||
python -c "import sys, pydantic; print('compiled:', pydantic.compiled); sys.exit(0 if pydantic.compiled else 1)"
|
||||
ls -alh
|
||||
ls -alh pydantic/
|
||||
|
||||
- run: mkdir coverage
|
||||
|
||||
- name: test
|
||||
run: make test
|
||||
env:
|
||||
COVERAGE_FILE: coverage/.coverage.linux-py${{ matrix.python-version }}-compiled
|
||||
CONTEXT: linux-py${{ matrix.python-version }}-compiled
|
||||
|
||||
- name: store coverage files
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: coverage
|
||||
path: coverage
|
||||
|
||||
test-not-compiled:
|
||||
test:
|
||||
name: test py${{ matrix.python-version }} on ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu, macos, windows]
|
||||
python-version: ['3.7', '3.8', '3.9', '3.10']
|
||||
include:
|
||||
- os: ubuntu
|
||||
python-version: ['3.7', '3.8', '3.9', '3.10', '3.11.0-rc.1']
|
||||
|
||||
env:
|
||||
PYTHON: ${{ matrix.python-version }}
|
||||
OS: ${{ matrix.os }}
|
||||
COMPILED: no
|
||||
DEPS: yes
|
||||
|
||||
runs-on: ${{ matrix.os }}-latest
|
||||
@@ -177,40 +108,31 @@ jobs:
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- uses: actions/cache@v3
|
||||
id: cache
|
||||
with:
|
||||
path: ${{ env.pythonLocation }}
|
||||
key: >
|
||||
test-not-compiled
|
||||
${{ runner.os }}
|
||||
${{ env.pythonLocation }}
|
||||
${{ hashFiles('setup.py') }}
|
||||
${{ hashFiles('requirements.txt') }}
|
||||
${{ hashFiles('tests/requirements-testing.txt') }}
|
||||
- name: install min deps
|
||||
run: pip install -r requirements/pyproject-min.txt -r requirements/testing.txt
|
||||
|
||||
- name: install
|
||||
run: make install-testing
|
||||
- name: install pydantic
|
||||
run: pip install .
|
||||
|
||||
- run: pip freeze
|
||||
|
||||
- run: mkdir coverage
|
||||
|
||||
- name: test with deps
|
||||
run: make test
|
||||
env:
|
||||
COVERAGE_FILE: coverage/.coverage.${{ runner.os }}-py${{ matrix.python-version }}-with-deps
|
||||
CONTEXT: ${{ runner.os }}-py${{ matrix.python-version }}-with-deps
|
||||
|
||||
- name: uninstall deps
|
||||
run: pip uninstall -y cython email-validator devtools python-dotenv
|
||||
|
||||
- name: test without deps
|
||||
run: make test
|
||||
env:
|
||||
COVERAGE_FILE: coverage/.coverage.${{ runner.os }}-py${{ matrix.python-version }}-without-deps
|
||||
CONTEXT: ${{ runner.os }}-py${{ matrix.python-version }}-without-deps
|
||||
|
||||
- name: install extra deps
|
||||
run: pip install -r requirements/pyproject-all.txt -r requirements/testing-extra.txt
|
||||
|
||||
- name: test with deps
|
||||
run: make test
|
||||
env:
|
||||
COVERAGE_FILE: coverage/.coverage.${{ runner.os }}-py${{ matrix.python-version }}-with-deps
|
||||
CONTEXT: ${{ runner.os }}-py${{ matrix.python-version }}-with-deps
|
||||
|
||||
- name: store coverage files
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
@@ -223,7 +145,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
mypy-version: ['0.910', '0.921', '0.931', '0.942', '0.950', '0.960']
|
||||
mypy-version: ['0.930', '0.942', '0.950', '0.961']
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -233,21 +155,30 @@ jobs:
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- uses: actions/cache@v3
|
||||
id: cache
|
||||
with:
|
||||
path: ${{ env.pythonLocation }}
|
||||
key: >
|
||||
test-mypy
|
||||
${{ runner.os }}
|
||||
${{ env.pythonLocation }}
|
||||
${{ hashFiles('requirements/pyproject-min.txt') }}
|
||||
${{ hashFiles('requirements/testing.txt') }}
|
||||
${{ matrix.mypy-version }}
|
||||
|
||||
- name: install
|
||||
run: |
|
||||
make install-testing
|
||||
pip freeze
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: pip install -r requirements/pyproject-min.txt -r requirements/testing.txt
|
||||
|
||||
- name: uninstall deps
|
||||
run: pip uninstall -y mypy tomli toml
|
||||
|
||||
- name: install specific mypy version
|
||||
- name: install mypy
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: pip install mypy==${{ matrix.mypy-version }}
|
||||
|
||||
- run: mkdir coverage
|
||||
|
||||
- name: run tests
|
||||
run: pytest --cov=pydantic tests/mypy
|
||||
run: coverage run -m pytest tests/mypy
|
||||
env:
|
||||
COVERAGE_FILE: coverage/.coverage.linux-py3.10-mypy${{ matrix.mypy-version }}
|
||||
CONTEXT: linux-py3.10-mypy${{ matrix.mypy-version }}
|
||||
@@ -259,7 +190,7 @@ jobs:
|
||||
path: coverage
|
||||
|
||||
coverage-combine:
|
||||
needs: [test-linux-compiled, test-not-compiled, test-old-mypy]
|
||||
needs: [test, test-old-mypy]
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
@@ -275,7 +206,7 @@ jobs:
|
||||
name: coverage
|
||||
path: coverage
|
||||
|
||||
- run: pip install coverage
|
||||
- run: pip install coverage[toml]
|
||||
|
||||
- run: ls -la coverage
|
||||
- run: coverage combine coverage
|
||||
@@ -288,87 +219,29 @@ jobs:
|
||||
name: coverage-html
|
||||
path: htmlcov
|
||||
|
||||
test-fastapi:
|
||||
name: test fastAPI
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: set up python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: install
|
||||
run: make install-testing
|
||||
|
||||
- name: test
|
||||
run: make test-fastapi
|
||||
|
||||
build:
|
||||
name: build py3.${{ matrix.python-version }} on ${{ matrix.platform || matrix.os }}
|
||||
needs: [lint, test-linux-compiled, test-not-compiled, test-old-mypy, test-fastapi]
|
||||
if: "success() && (startsWith(github.ref, 'refs/tags/') || github.ref == 'refs/heads/main')"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu , macos , windows]
|
||||
python-version: ['7', '8', '9', '10', '11']
|
||||
include:
|
||||
- os: ubuntu
|
||||
platform: linux
|
||||
- os: windows
|
||||
ls: dir
|
||||
|
||||
runs-on: ${{ matrix.os }}-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: set up python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.8'
|
||||
|
||||
- name: install
|
||||
run: pip install -U twine setuptools wheel cibuildwheel
|
||||
|
||||
- name: build sdist
|
||||
if: matrix.os == 'ubuntu' && matrix.python-version == '9'
|
||||
run: python setup.py sdist bdist_wheel
|
||||
env:
|
||||
SKIP_CYTHON: 1
|
||||
|
||||
- name: build ${{ matrix.platform || matrix.os }} binaries
|
||||
run: cibuildwheel --output-dir dist
|
||||
env:
|
||||
PIP: 'pip'
|
||||
CIBW_BUILD: 'cp3${{ matrix.python-version }}-*'
|
||||
CIBW_SKIP: '*-win32'
|
||||
CIBW_PLATFORM: '${{ matrix.platform || matrix.os }}'
|
||||
CIBW_BEFORE_BUILD: 'pip install -U cython'
|
||||
CIBW_TEST_REQUIRES: 'pytest==6.2.5 pytest-mock==3.6.1'
|
||||
CIBW_TEST_COMMAND: 'pytest {project}/tests'
|
||||
CIBW_MANYLINUX_X86_64_IMAGE: 'manylinux2014'
|
||||
CIBW_MANYLINUX_I686_IMAGE: 'manylinux2014'
|
||||
CIBW_ARCHS_MACOS: 'x86_64 arm64'
|
||||
CIBW_TEST_SKIP: '*-macosx_arm64' # see https://cibuildwheel.readthedocs.io/en/stable/faq/#universal2
|
||||
|
||||
# TODO build windows 32bit binaries
|
||||
|
||||
- name: list dist files
|
||||
run: |
|
||||
${{ matrix.ls || 'ls -lh' }} dist/
|
||||
twine check dist/*
|
||||
|
||||
- name: Store dist artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: pypi_files
|
||||
path: dist
|
||||
# FastAPI has a version constraint of pydantic<2.0.0, so we can't run tests, we expect them to break for now anyway
|
||||
# test-fastapi:
|
||||
# name: test fastAPI
|
||||
# runs-on: ubuntu-latest
|
||||
# steps:
|
||||
# - uses: actions/checkout@v3
|
||||
#
|
||||
# - name: set up python
|
||||
# uses: actions/setup-python@v4
|
||||
# with:
|
||||
# python-version: '3.10'
|
||||
#
|
||||
# - name: install
|
||||
# run: |
|
||||
# pip install -r requirements/pyproject-all.txt
|
||||
# pip install .
|
||||
#
|
||||
# - name: test
|
||||
# run: make test-fastapi
|
||||
|
||||
deploy:
|
||||
name: Deploy
|
||||
needs: build
|
||||
needs: [lint, docs-build, test, test-old-mypy] # TODO re-add test-fastapi once fixed
|
||||
if: "success() && startsWith(github.ref, 'refs/tags/')"
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -380,12 +253,6 @@ jobs:
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: get dist artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: pypi_files
|
||||
path: dist
|
||||
|
||||
- name: get docs
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
@@ -393,17 +260,18 @@ jobs:
|
||||
path: site
|
||||
|
||||
- name: install
|
||||
run: pip install -U twine packaging
|
||||
|
||||
- name: twine check
|
||||
run: |
|
||||
twine check dist/*
|
||||
ls -lh dist
|
||||
run: pip install -U twine build packaging
|
||||
|
||||
- name: check tag
|
||||
id: check-tag
|
||||
run: ./tests/check_tag.py
|
||||
|
||||
- name: build
|
||||
run: python -m build
|
||||
|
||||
- run: ls -lh dist
|
||||
- run: twine check dist/*
|
||||
|
||||
- name: upload to pypi
|
||||
run: twine upload dist/*
|
||||
env:
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
# from https://github.com/hrvey/combine-prs-workflow/blob/master/combine-prs.yml
|
||||
name: 'Combine Dependabot PRs'
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
branchPrefix:
|
||||
description: 'Branch prefix to find combinable PRs based on'
|
||||
required: true
|
||||
default: 'dependabot/'
|
||||
mustBeGreen:
|
||||
description: 'Only combine PRs that are green'
|
||||
required: true
|
||||
default: true
|
||||
combineBranchName:
|
||||
description: 'Name of the branch to combine PRs into'
|
||||
required: true
|
||||
default: 'combine-dependabot-bumps'
|
||||
ignoreLabel:
|
||||
description: 'Exclude PRs with this label'
|
||||
required: true
|
||||
default: 'nocombine'
|
||||
|
||||
jobs:
|
||||
combine-prs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/github-script@v6
|
||||
id: fetch-branch-names
|
||||
name: Fetch branch names
|
||||
with:
|
||||
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||
script: |
|
||||
const pulls = await github.paginate('GET /repos/:owner/:repo/pulls', {
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo
|
||||
});
|
||||
branches = [];
|
||||
prs = [];
|
||||
base_branch = null;
|
||||
for (const pull of pulls) {
|
||||
const branch = pull['head']['ref'];
|
||||
console.log('Pull for branch: ' + branch);
|
||||
if (branch.startsWith('${{ github.event.inputs.branchPrefix }}')) {
|
||||
console.log('Branch matched: ' + branch);
|
||||
statusOK = true;
|
||||
if(${{ github.event.inputs.mustBeGreen }}) {
|
||||
console.log('Checking green status: ' + branch);
|
||||
const statuses = await github.paginate('GET /repos/{owner}/{repo}/commits/{ref}/status', {
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
ref: branch
|
||||
});
|
||||
if(statuses.length > 0) {
|
||||
const latest_status = statuses[0]['state'];
|
||||
console.log('Validating status: ' + latest_status);
|
||||
if(latest_status != 'success') {
|
||||
console.log('Discarding ' + branch + ' with status ' + latest_status);
|
||||
statusOK = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log('Checking labels: ' + branch);
|
||||
const labels = pull['labels'];
|
||||
for(const label of labels) {
|
||||
const labelName = label['name'];
|
||||
console.log('Checking label: ' + labelName);
|
||||
if(labelName == '${{ github.event.inputs.ignoreLabel }}') {
|
||||
console.log('Discarding ' + branch + ' with label ' + labelName);
|
||||
statusOK = false;
|
||||
}
|
||||
}
|
||||
if (statusOK) {
|
||||
console.log('Adding branch to array: ' + branch);
|
||||
branches.push(branch);
|
||||
prs.push('#' + pull['number'] + ' ' + pull['title']);
|
||||
base_branch = pull['base']['ref'];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (branches.length == 0) {
|
||||
core.setFailed('No PRs/branches matched criteria');
|
||||
return;
|
||||
}
|
||||
core.setOutput('base-branch', base_branch);
|
||||
core.setOutput('prs-string', prs.join('\n'));
|
||||
|
||||
combined = branches.join(' ')
|
||||
console.log('Combined: ' + combined);
|
||||
return combined
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# Creates a branch with other PR branches merged together
|
||||
- name: Created combined branch
|
||||
env:
|
||||
BASE_BRANCH: ${{ steps.fetch-branch-names.outputs.base-branch }}
|
||||
BRANCHES_TO_COMBINE: ${{ steps.fetch-branch-names.outputs.result }}
|
||||
COMBINE_BRANCH_NAME: ${{ github.event.inputs.combineBranchName }}
|
||||
run: |
|
||||
echo "$BRANCHES_TO_COMBINE"
|
||||
sourcebranches="${BRANCHES_TO_COMBINE%\"}"
|
||||
sourcebranches="${sourcebranches#\"}"
|
||||
|
||||
basebranch="${BASE_BRANCH%\"}"
|
||||
basebranch="${basebranch#\"}"
|
||||
|
||||
git config pull.rebase false
|
||||
git config user.name github-actions
|
||||
git config user.email github-actions@github.com
|
||||
|
||||
git branch $COMBINE_BRANCH_NAME $basebranch
|
||||
git checkout $COMBINE_BRANCH_NAME
|
||||
git pull origin $sourcebranches --no-edit
|
||||
git push origin $COMBINE_BRANCH_NAME
|
||||
|
||||
# Creates a PR with the new combined branch
|
||||
- uses: actions/github-script@v6
|
||||
name: Create Combined Pull Request
|
||||
env:
|
||||
PRS_STRING: ${{ steps.fetch-branch-names.outputs.prs-string }}
|
||||
with:
|
||||
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||
script: |
|
||||
const prString = process.env.PRS_STRING;
|
||||
const body = 'This PR was created by the Combine PRs action by combining the following PRs:\n' + prString;
|
||||
await github.pulls.create({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
title: 'Combined Dependabot Bumps',
|
||||
head: '${{ github.event.inputs.combineBranchName }}',
|
||||
base: '${{ steps.fetch-branch-names.outputs.base-branch }}',
|
||||
body: body
|
||||
});
|
||||
@@ -1,10 +1,12 @@
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.0.1
|
||||
rev: v4.3.0
|
||||
hooks:
|
||||
- id: check-yaml
|
||||
args: ['--unsafe']
|
||||
- id: check-toml
|
||||
- id: end-of-file-fixer
|
||||
- id: trailing-whitespace
|
||||
|
||||
- repo: local
|
||||
hooks:
|
||||
@@ -13,13 +15,16 @@ repos:
|
||||
entry: make lint
|
||||
types: [python]
|
||||
language: system
|
||||
pass_filenames: false
|
||||
- id: mypy
|
||||
name: Mypy
|
||||
entry: make mypy
|
||||
types: [python]
|
||||
language: system
|
||||
pass_filenames: false
|
||||
- id: pyupgrade
|
||||
name: Pyupgrade
|
||||
entry: make pyupgrade
|
||||
entry: pyupgrade --py37-plus
|
||||
types: [python]
|
||||
language: system
|
||||
exclude: ^docs/.*$
|
||||
|
||||
+32
-32
@@ -1,8 +1,8 @@
|
||||
## v1.10.2 (2022-09-05)
|
||||
|
||||
* **Revert Change:** Revert percent encoding of URL parts which was originally added in #4224, #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
|
||||
* 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 by @samuelcolvin
|
||||
* fix: dataclass wrapper was not always called, #4477 by @PrettyWood
|
||||
* Use `tomllib` on Python 3.11 when parsing `mypy` configuration, #4476 by @hauntsaninja
|
||||
@@ -40,7 +40,7 @@
|
||||
* fix "extra fields not permitted" error when dataclass with `Extra.forbid` is validated multiple times, #4343 by @detachhead
|
||||
* Add Python 3.9 and 3.10 examples to docs, #4339 by @Bobronium
|
||||
* Discriminated union models now use `oneOf` instead of `anyOf` when generating OpenAPI schema definitions, #4335 by @MaxwellPayne
|
||||
* Allow type checkers to infer inner type of `Json` type. `Json[list[str]]` will be now inferred as `list[str]`,
|
||||
* 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 by @Bobronium
|
||||
* Allow empty string aliases by using a `alias is not None` check, rather than `bool(alias)`, #4253 by @sergeytsaplin
|
||||
@@ -112,23 +112,23 @@ Pre-release, see [the GitHub release](https://github.com/pydantic/pydantic/relea
|
||||
## 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,
|
||||
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 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'`,
|
||||
`'none'`, `'deep'`, or `'shallow'` corresponding to not copying, deep copy & shallow copy; default `'shallow'`,
|
||||
#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,
|
||||
@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`
|
||||
* Limit the size of `generics._generic_types_cache` and `generics._assigned_parameters`
|
||||
to avoid unlimited increase in memory usage, #4083 by @samuelcolvin
|
||||
* Add Jupyverse and FPS as Jupyter projects using pydantic, #4082 by @davidbrochart
|
||||
* Speedup `__isinstancecheck__` on pydantic models when the type is not a model, may also avoid memory "leaks", #4081 by @samuelcolvin
|
||||
@@ -152,7 +152,7 @@ for their kind support.
|
||||
|
||||
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,
|
||||
@es3n1n, @jokull, @JonasKs, @Rehket, @corleyma, @daddycocoaman, @hardbyte, @datarootsio, @jodal, @aminalaee, @rafsaf,
|
||||
@jqueguiner, @chdsbd, @kevinalh, @Mazyod, @grillazz, @JonasKs, @simw, @leynier, @xfenix
|
||||
for their kind support.
|
||||
|
||||
@@ -185,7 +185,7 @@ for their kind support.
|
||||
|
||||
### v1.9.0a1 (2021-12-18) Changes
|
||||
|
||||
* Add support for `Decimal`-specific validation configurations in `Field()`, additionally to using `condecimal()`,
|
||||
* Add support for `Decimal`-specific validation configurations in `Field()`, additionally to using `condecimal()`,
|
||||
to allow better support from editors and tooling, #3507 by @tiangolo
|
||||
* Add `arm64` binaries suitable for MacOS with an M1 CPU to PyPI, #3498 by @samuelcolvin
|
||||
* Fix issue where `None` was considered invalid when using a `Union` type containing `Any` or `object`, #3444 by @tharradine
|
||||
@@ -193,7 +193,7 @@ for their kind support.
|
||||
`pydantic.fields.ModelField`) to `__modify_schema__()` if present, #3434 by @jasujm
|
||||
* Fix issue when pydantic fail to parse `typing.ClassVar` string type annotation, #3401 by @uriyyo
|
||||
* Mention Python >= 3.9.2 as an alternative to `typing_extensions.TypedDict`, #3374 by @BvB93
|
||||
* Changed the validator method name in the [Custom Errors example](https://pydantic-docs.helpmanual.io/usage/models/#custom-errors)
|
||||
* Changed the validator method name in the [Custom Errors example](https://pydantic-docs.helpmanual.io/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 by @michaelrios28
|
||||
* Add `AmqpDsn` class, #3254 by @kludex
|
||||
* Always use `Enum` value as default in generated JSON schema, #3190 by @joaommartins
|
||||
@@ -211,19 +211,19 @@ for their kind support.
|
||||
* Make multiple inheritance work when using `PrivateAttr`, #2989 by @hmvp
|
||||
* Parse environment variables as JSON, if they have a `Union` type with a complex subfield, #2936 by @cbartz
|
||||
* Prevent `StrictStr` permitting `Enum` values where the enum inherits from `str`, #2929 by @samuelcolvin
|
||||
* Make `SecretsSettingsSource` parse values being assigned to fields of complex types when sourced from a secrets file,
|
||||
* 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 by @davidmreed
|
||||
* add a dark mode to _pydantic_ documentation, #2913 by @gbdlin
|
||||
* Make `pydantic-mypy` plugin compatible with `pyproject.toml` configuration, consistent with `mypy` changes.
|
||||
* Make `pydantic-mypy` plugin compatible with `pyproject.toml` configuration, consistent with `mypy` changes.
|
||||
See the [doc](https://pydantic-docs.helpmanual.io/mypy_plugin/#configuring-the-plugin) for more information, #2908 by @jrwalk
|
||||
* add Python 3.10 support, #2885 by @PrettyWood
|
||||
* Correctly parse generic models with `Json[T]`, #2860 by @geekingfrog
|
||||
* Update contrib docs re: Python version to use for building docs, #2856 by @paxcodes
|
||||
* Clarify documentation about _pydantic_'s support for custom validation and strict type checking,
|
||||
* Clarify documentation about _pydantic_'s support for custom validation and strict type checking,
|
||||
despite _pydantic_ being primarily a parsing library, #2855 by @paxcodes
|
||||
* Fix schema generation for `Deque` fields, #2810 by @sergejkozin
|
||||
* fix an edge case when mixing constraints and `Literal`, #2794 by @PrettyWood
|
||||
* Fix postponed annotation resolution for `NamedTuple` and `TypedDict` when they're used directly as the type of fields
|
||||
* Fix postponed annotation resolution for `NamedTuple` and `TypedDict` when they're used directly as the type of fields
|
||||
within Pydantic models, #2760 by @jameysharp
|
||||
* Fix bug when `mypy` plugin fails on `construct` method call for `BaseSettings` derived classes, #2753 by @uriyyo
|
||||
* Add function overloading for a `pydantic.create_model` function, #2748 by @uriyyo
|
||||
@@ -246,7 +246,7 @@ for their kind support.
|
||||
and `postgresql+pygresql` schemes for `PostgresDsn`, #2567 by @postgres-asyncpg
|
||||
* Enable the Hypothesis plugin to generate a constrained decimal when the `decimal_places` argument is specified, #2524 by @cwe5590
|
||||
* Allow `collections.abc.Callable` to be used as type in Python 3.9, #2519 by @daviskirk
|
||||
* Documentation update how to custom compile pydantic when using pip install, small change in `setup.py`
|
||||
* Documentation update how to custom compile pydantic when using pip install, small change in `setup.py`
|
||||
to allow for custom CFLAGS when compiling, #2517 by @peterroelants
|
||||
* remove side effect of `default_factory` to run it only once even if `Config.validate_all` is set, #2515 by @PrettyWood
|
||||
* Add lookahead to ip regexes for `AnyUrl` hosts. This allows urls with DNS labels
|
||||
@@ -259,7 +259,7 @@ for their kind support.
|
||||
* Add `PastDate` and `FutureDate` types, #2425 by @Kludex
|
||||
* Support generating schema for `Generic` fields with subtypes, #2375 by @maximberg
|
||||
* fix(encoder): serialize `NameEmail` to str, #2341 by @alecgerona
|
||||
* add `Config.smart_union` to prevent coercion in `Union` if possible, see
|
||||
* add `Config.smart_union` to prevent coercion in `Union` if possible, see
|
||||
[the doc](https://pydantic-docs.helpmanual.io/usage/model_config/#smart-union) for more information, #2092 by @PrettyWood
|
||||
* Add ability to use `typing.Counter` as a model field type, #2060 by @uriyyo
|
||||
* Add parameterised subclasses to `__bases__` when constructing new parameterised classes, so that `A <: B => A[int] <: B[int]`, #2007 by @diabolo-dan
|
||||
@@ -276,8 +276,8 @@ for their kind support.
|
||||
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,
|
||||
* **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 by @PrettyWood
|
||||
* fix JSON schema generation with a `Literal` of an enum member, #2536 by @PrettyWood
|
||||
@@ -289,7 +289,7 @@ for their kind support.
|
||||
|
||||
## v1.8.1 (2021-03-03)
|
||||
|
||||
Bug fixes for regressions and new features from `v1.8`
|
||||
Bug fixes for regressions and new features from `v1.8`
|
||||
|
||||
* allow elements of `Config.field` to update elements of a `Field`, #2461 by @samuelcolvin
|
||||
* fix validation with a `BaseModel` field and a custom root type, #2449 by @PrettyWood
|
||||
@@ -303,8 +303,8 @@ Bug fixes for regressions and new features from `v1.8`
|
||||
## 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,
|
||||
@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.
|
||||
|
||||
@@ -395,7 +395,7 @@ for their kind support.
|
||||
|
||||
## v1.7.4 (2021-05-11)
|
||||
|
||||
* **Security fix:** Fix `date` and `datetime` parsing so passing either `'infinity'` or `float('inf')`
|
||||
* **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)
|
||||
|
||||
@@ -434,7 +434,7 @@ for their kind support.
|
||||
## v1.7 (2020-10-26)
|
||||
|
||||
Thank you to pydantic's sponsors:
|
||||
@timdrijvers, @BCarley, @chdsbd, @tiangolo, @matin, @linusg, @kevinalh, @jorgecarleitao, @koxudaxi, @primer-api
|
||||
@timdrijvers, @BCarley, @chdsbd, @tiangolo, @matin, @linusg, @kevinalh, @jorgecarleitao, @koxudaxi, @primer-api
|
||||
for their kind support.
|
||||
|
||||
### Highlights
|
||||
@@ -449,7 +449,7 @@ for their kind support.
|
||||
* **Breaking Change:** remove `__field_defaults__`, add `default_factory` support with `BaseModel.construct`.
|
||||
Use `.get_default()` method on fields in `__fields__` attribute instead, #1732 by @PrettyWood
|
||||
* Rearrange CI to run linting as a separate job, split install recipes for different tasks, #2020 by @samuelcolvin
|
||||
* Allows subclasses of generic models to make some, or all, of the superclass's type parameters concrete, while
|
||||
* 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 by @choogeboom
|
||||
* Call validator with the correct `values` parameter type in `BaseModel.__setattr__`,
|
||||
when `validate_assignment = True` in model config, #1999 by @me-ransh
|
||||
@@ -470,17 +470,17 @@ for their kind support.
|
||||
* add basic support of Pattern type in schema generation, #1767 by @PrettyWood
|
||||
* Support custom title, description and default in schema of enums, #1748 by @PrettyWood
|
||||
* Properly represent `Literal` Enums when `use_enum_values` is True, #1747 by @noelevans
|
||||
* Allows timezone information to be added to strings to be formatted as time objects. Permitted formats are `Z` for UTC
|
||||
* 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 by @noelevans
|
||||
* Add stub `__init__` with Python 3.6 signature for `ForwardRef`, #1738 by @sirtelemak
|
||||
* Fix behaviour with forward refs and optional fields in nested models, #1736 by @PrettyWood
|
||||
* add `Enum` and `IntEnum` as valid types for fields, #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
|
||||
* 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 by @Bobronium
|
||||
* Add private attributes support, #1679 by @Bobronium
|
||||
* add `config` to `@validate_arguments`, #1663 by @samuelcolvin
|
||||
* Allow descendant Settings models to override env variable names for the fields defined in parent Settings models with
|
||||
* 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 by @ojomio
|
||||
* Support `ref_template` when creating schema `$ref`s, #1479 by @kilo59
|
||||
* Add a `__call__` stub to `PyObject` so that mypy will know that it is callable, #1352 by @brianmaissy
|
||||
@@ -490,7 +490,7 @@ for their kind support.
|
||||
|
||||
## v1.6.2 (2021-05-11)
|
||||
|
||||
* **Security fix:** Fix `date` and `datetime` parsing so passing either `'infinity'` or `float('inf')`
|
||||
* **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)
|
||||
|
||||
@@ -559,7 +559,7 @@ Thank you to pydantic's sponsors: @matin, @tiangolo, @chdsbd, @jorgecarleitao, a
|
||||
* Remove `typing_extensions` dependency for Python 3.8, #1342 by @prettywood
|
||||
* Make `SecretStr` and `SecretBytes` initialization idempotent, #1330 by @atheuz
|
||||
* document making secret types dumpable using the json method, #1328 by @atheuz
|
||||
* Move all testing and build to github actions, add windows and macos binaries,
|
||||
* Move all testing and build to github actions, add windows and macos binaries,
|
||||
thank you @StephenBrown2 for much help, #1326 by @samuelcolvin
|
||||
* fix card number length check in `PaymentCardNumber`, `PaymentCardBrand` now inherits from `str`, #1317 by @samuelcolvin
|
||||
* Have `BaseModel` inherit from `Representation` to make mypy happy when overriding `__str__`, #1310 by @FuegoFro
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017, 2018, 2019, 2020, 2021 Samuel Colvin and other contributors
|
||||
Copyright (c) 2017 - 2022 Samuel Colvin and other 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
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
include LICENSE
|
||||
include README.md
|
||||
include HISTORY.md
|
||||
graft tests
|
||||
global-exclude __pycache__
|
||||
global-exclude *.py[cod]
|
||||
@@ -1,56 +1,23 @@
|
||||
.DEFAULT_GOAL := all
|
||||
sources = pydantic tests docs/build
|
||||
isort = isort $(sources)
|
||||
black = black -S -l 120 --target-version py38 $(sources)
|
||||
|
||||
.PHONY: install-linting
|
||||
install-linting:
|
||||
pip install -r tests/requirements-linting.txt
|
||||
pre-commit install
|
||||
|
||||
.PHONY: install-pydantic
|
||||
install-pydantic:
|
||||
python -m pip install -U wheel pip
|
||||
pip install -r requirements.txt
|
||||
SKIP_CYTHON=1 pip install -e .
|
||||
|
||||
.PHONY: install-testing
|
||||
install-testing: install-pydantic
|
||||
pip install -r tests/requirements-testing.txt
|
||||
|
||||
.PHONY: install-docs
|
||||
install-docs: install-pydantic
|
||||
pip install -U -r docs/requirements.txt
|
||||
|
||||
.PHONY: install
|
||||
install: install-testing install-linting install-docs
|
||||
@echo 'installed development requirements'
|
||||
|
||||
.PHONY: build-trace
|
||||
build-trace:
|
||||
python setup.py build_ext --force --inplace --define CYTHON_TRACE
|
||||
|
||||
.PHONY: build
|
||||
build:
|
||||
python setup.py build_ext --inplace
|
||||
install:
|
||||
python -m pip install -U pip
|
||||
pip install -r requirements/all.txt
|
||||
pip install -e .
|
||||
|
||||
.PHONY: format
|
||||
format:
|
||||
pyupgrade --py37-plus --exit-zero-even-if-changed `find $(sources) -name "*.py" -type f`
|
||||
$(isort)
|
||||
$(black)
|
||||
pyupgrade --py37-plus --exit-zero-even-if-changed `find $(sources) -name "*.py" -type f`
|
||||
isort $(sources)
|
||||
black $(sources)
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
flake8 $(sources)
|
||||
$(isort) --check-only --df
|
||||
$(black) --check --diff
|
||||
|
||||
.PHONY: check-dist
|
||||
check-dist:
|
||||
python setup.py check -ms
|
||||
SKIP_CYTHON=1 python setup.py sdist
|
||||
twine check dist/*
|
||||
isort $(sources) --check-only --df
|
||||
black $(sources) --check --diff
|
||||
|
||||
.PHONY: mypy
|
||||
mypy:
|
||||
@@ -66,7 +33,7 @@ pyright:
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
pytest --cov=pydantic
|
||||
coverage run -m pytest --durations=10
|
||||
|
||||
.PHONY: testcov
|
||||
testcov: test
|
||||
@@ -107,7 +74,6 @@ clean:
|
||||
rm -rf build
|
||||
rm -rf dist
|
||||
rm -f pydantic/*.c pydantic/*.so
|
||||
python setup.py clean
|
||||
rm -rf site
|
||||
rm -rf docs/_build
|
||||
rm -rf docs/.changelog.md docs/.version.md docs/.tmp_schema_mappings.html
|
||||
|
||||
@@ -8,7 +8,19 @@
|
||||
[](https://github.com/pydantic/pydantic)
|
||||
[](https://github.com/pydantic/pydantic/blob/main/LICENSE)
|
||||
|
||||
Data validation and settings management using Python type hints.
|
||||
Data validation using Python type hints.
|
||||
|
||||
---
|
||||
|
||||
## Notice
|
||||
|
||||
**This branch relates to development of pydantic V2 which is not yet ready for release.**
|
||||
|
||||
If you're a user of pydantic, you probably want either
|
||||
[pydantic V1.10 Documentation](https://pydantic-docs.helpmanual.io/) or,
|
||||
[`1.10.X-fixes` git branch](https://github.com/pydantic/pydantic/tree/1.10.X-fixes).
|
||||
|
||||
---
|
||||
|
||||
Fast and extensible, *pydantic* plays nicely with your linters/IDE/brain.
|
||||
Define how data should be in pure, canonical Python 3.7+; validate it with *pydantic*.
|
||||
|
||||
+10
-10
@@ -32,9 +32,9 @@ Here goes...
|
||||
---
|
||||
|
||||
Enormous thanks to
|
||||
[Eric Jolibois](https://github.com/PrettyWood), [Laurence Watson](https://github.com/Rabscuttler),
|
||||
[Sebastián Ramírez](https://github.com/tiangolo), [Adrian Garcia Badaracco](https://github.com/adriangb),
|
||||
[Tom Hamilton Stubber](https://github.com/tomhamiltonstubber), [Zac Hatfield-Dodds](https://github.com/Zac-HD),
|
||||
[Eric Jolibois](https://github.com/PrettyWood), [Laurence Watson](https://github.com/Rabscuttler),
|
||||
[Sebastián Ramírez](https://github.com/tiangolo), [Adrian Garcia Badaracco](https://github.com/adriangb),
|
||||
[Tom Hamilton Stubber](https://github.com/tomhamiltonstubber), [Zac Hatfield-Dodds](https://github.com/Zac-HD),
|
||||
[Tom](https://github.com/czotomo) & [Hasan Ramezani](https://github.com/hramezani)
|
||||
for reviewing this blog post, putting up with (and correcting) my horrible typos and making great suggestions
|
||||
that have made this post and Pydantic V2 materially better.
|
||||
@@ -207,7 +207,7 @@ In future direct validation of JSON will also allow:
|
||||
!!! note
|
||||
Pydantic has always had special support for JSON, that is not going to change.
|
||||
|
||||
While in theory other formats could be specifically supported, the overheads and development time are
|
||||
While in theory other formats could be specifically supported, the overheads and development time are
|
||||
significant and I don't think there's another format that's
|
||||
used widely enough to be worth specific logic. Other formats can be parsed to python then validated, similarly
|
||||
when serialising, data can be exported to a python object, then serialised,
|
||||
@@ -215,7 +215,7 @@ In future direct validation of JSON will also allow:
|
||||
|
||||
### Validation without a Model :thumbsup:
|
||||
|
||||
In pydantic V1 the core of all validation was a pydantic model, this led to a significant performance penalty
|
||||
In pydantic V1 the core of all validation was a pydantic model, this led to a significant performance penalty
|
||||
and extra complexity when the output data type was not a model.
|
||||
|
||||
pydantic-core operates on a tree of validators with no "model" type required at the base of that tree.
|
||||
@@ -278,13 +278,13 @@ class MyModel(BaseModel):
|
||||
@validator('timestamp', mode='wrap')
|
||||
def validate_timestamp(cls, v, handler):
|
||||
if v == 'now':
|
||||
# we don't want to bother with further validation,
|
||||
# we don't want to bother with further validation,
|
||||
# just return the new value
|
||||
return datetime.now()
|
||||
try:
|
||||
return handler(v)
|
||||
except ValidationError:
|
||||
# validation failed, in this case we want to
|
||||
# validation failed, in this case we want to
|
||||
# return a default value
|
||||
return datetime(2000, 1, 1)
|
||||
```
|
||||
@@ -366,7 +366,7 @@ from pydantic import BaseModel, EmailStr, validator
|
||||
class User(BaseModel):
|
||||
email: EmailStr
|
||||
home_country: str
|
||||
|
||||
|
||||
@validator('home_country')
|
||||
def check_home_country(cls, v, context):
|
||||
if v not in context['countries']:
|
||||
@@ -735,7 +735,7 @@ The emoji here is just for variation, I'm not frowning about any of this, these
|
||||
|
||||
1. `__root__` custom root models are no longer necessary since validation on any supported data type is allowed
|
||||
without a model
|
||||
2. `.parse_file()` and `.parse_raw()`, partially replaced with `.model_validate_json()`,
|
||||
2. `.parse_file()` and `.parse_raw()`, partially replaced with `.model_validate_json()`,
|
||||
see [model methods](#model-namespace-cleanup)
|
||||
3. `.schema_json()` & `.copy()`, see [model methods](#model-namespace-cleanup)
|
||||
4. `TypeError` are no longer considered as validation errors, but rather as internal errors, this is to better
|
||||
@@ -759,7 +759,7 @@ The emoji here is just for variation, I'm not frowning about any of this, these
|
||||
* `json_encoders` - see the export "mode" discussion [above](#improvements-to-dumpingserializationexport)
|
||||
* `underscore_attrs_are_private` we should just choose a sensible default
|
||||
* `smart_union` - all unions are now "smart"
|
||||
9. `dict(model)` functionality should be removed, there's a much clearer distinction now that in 2017 when I
|
||||
9. `dict(model)` functionality should be removed, there's a much clearer distinction now that in 2017 when I
|
||||
implemented this between a model and a dict
|
||||
|
||||
## Features Remaining :neutral_face:
|
||||
|
||||
@@ -13,7 +13,7 @@ and [`st.from_type()`](https://hypothesis.readthedocs.io/en/latest/data.html#hyp
|
||||
strategies support them without any user configuration.
|
||||
|
||||
!!! warning
|
||||
Please note, while the plugin supports these types, hypothesis will(currently) generate values outside
|
||||
Please note, while the plugin supports these types, hypothesis will(currently) generate values outside
|
||||
of given args for the constrained function types.
|
||||
|
||||
|
||||
|
||||
+15
-15
@@ -102,9 +102,9 @@ If validation fails pydantic will raise an error with a breakdown of what was wr
|
||||
So *pydantic* uses some cool new language features, but why should I actually go and use it?
|
||||
|
||||
**plays nicely with your IDE/linter/brain**
|
||||
: There's no new schema definition micro-language to learn. If you know how to use Python type hints,
|
||||
you know how to use *pydantic*. Data structures are just instances of classes you define with type annotations,
|
||||
so auto-completion, linting, [mypy](usage/mypy.md), IDEs (especially [PyCharm](pycharm_plugin.md)),
|
||||
: There's no new schema definition micro-language to learn. If you know how to use Python type hints,
|
||||
you know how to use *pydantic*. Data structures are just instances of classes you define with type annotations,
|
||||
so auto-completion, linting, [mypy](usage/mypy.md), IDEs (especially [PyCharm](pycharm_plugin.md)),
|
||||
and your intuition should all work properly with your validated data.
|
||||
|
||||
**dual use**
|
||||
@@ -117,15 +117,15 @@ So *pydantic* uses some cool new language features, but why should I actually go
|
||||
it's generally as fast or faster than most similar libraries.
|
||||
|
||||
**validate complex structures**
|
||||
: use of [recursive *pydantic* models](usage/models.md#recursive-models), `typing`'s
|
||||
[standard types](usage/types.md#standard-library-types) (e.g. `List`, `Tuple`, `Dict` etc.) and
|
||||
: use of [recursive *pydantic* models](usage/models.md#recursive-models), `typing`'s
|
||||
[standard types](usage/types.md#standard-library-types) (e.g. `List`, `Tuple`, `Dict` etc.) and
|
||||
[validators](usage/validators.md) allow
|
||||
complex data schemas to be clearly and easily defined, validated, and parsed.
|
||||
|
||||
**extensible**
|
||||
: *pydantic* allows [custom data types](usage/types.md#custom-data-types) to be defined or you can extend validation
|
||||
: *pydantic* allows [custom data types](usage/types.md#custom-data-types) to be defined or you can extend validation
|
||||
with methods on a model decorated with the [`validator`](usage/validators.md) decorator.
|
||||
|
||||
|
||||
**dataclasses integration**
|
||||
: As well as `BaseModel`, *pydantic* provides
|
||||
a [`dataclass`](usage/dataclasses.md) decorator which creates (almost) vanilla Python dataclasses with input
|
||||
@@ -140,14 +140,14 @@ Hundreds of organisations and packages are using *pydantic*, including:
|
||||
fast to code and ready for production, based on *pydantic* and Starlette.
|
||||
|
||||
[Project Jupyter](https://jupyter.org/)
|
||||
: developers of the Jupyter notebook are using *pydantic*
|
||||
: 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), and for [FPS](https://github.com/jupyter-server/fps)'s
|
||||
configuration management.
|
||||
|
||||
**Microsoft**
|
||||
: are using *pydantic* (via FastAPI) for
|
||||
[numerous services](https://github.com/tiangolo/fastapi/pull/26#issuecomment-463768795), some of which are
|
||||
: are using *pydantic* (via FastAPI) for
|
||||
[numerous services](https://github.com/tiangolo/fastapi/pull/26#issuecomment-463768795), some of which are
|
||||
"getting integrated into the core Windows product and some Office products."
|
||||
|
||||
**Amazon Web Services**
|
||||
@@ -179,7 +179,7 @@ Hundreds of organisations and packages are using *pydantic*, including:
|
||||
[tools to debug and profile Python applications on Kubernetes](https://home.robusta.dev/python/) use
|
||||
*pydantic* models.
|
||||
|
||||
For a more comprehensive list of open-source projects using *pydantic* see the
|
||||
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).
|
||||
|
||||
## Discussion of Pydantic
|
||||
@@ -190,14 +190,14 @@ Podcasts and videos discussing pydantic.
|
||||
: Michael Kennedy and Samuel Colvin, the creator of *pydantic*, dive into the history of pydantic and its many uses and benefits.
|
||||
|
||||
[Podcast.\_\_init\_\_](https://www.pythonpodcast.com/pydantic-data-validation-episode-263/){target=_blank}
|
||||
: Discussion about where *pydantic* came from and ideas for where it might go next with
|
||||
: Discussion about where *pydantic* came from and ideas for where it might go next with
|
||||
Samuel Colvin the creator of pydantic.
|
||||
|
||||
[Python Bytes Podcast](https://pythonbytes.fm/episodes/show/157/oh-hai-pandas-hold-my-hand){target=_blank}
|
||||
: "*This is a sweet simple framework that solves some really nice problems... Data validations and settings management
|
||||
using Python type annotations, and it's the Python type annotations that makes me really extra happy... It works
|
||||
: "*This is a sweet simple framework that solves some really nice problems... Data validations and settings management
|
||||
using Python type annotations, and it's the Python type annotations that makes me really extra happy... It works
|
||||
automatically with all the IDE's you already have.*" --Michael Kennedy
|
||||
|
||||
[Python pydantic Introduction – Give your data classes super powers](https://www.youtube.com/watch?v=WJmqgJn9TXg){target=_blank}
|
||||
: a talk by Alexander Hultnér originally for the Python Pizza Conference introducing new users to pydantic and walking
|
||||
: a talk by Alexander Hultnér originally for the Python Pizza Conference introducing new users to pydantic and walking
|
||||
through the core features of pydantic.
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ conda install pydantic -c conda-forge
|
||||
|
||||
## Compiled with Cython
|
||||
|
||||
*pydantic* can optionally be compiled with [cython](https://cython.org/) which should give a 30-50% performance improvement.
|
||||
*pydantic* can optionally be compiled with [cython](https://cython.org/) which should give a 30-50% performance improvement.
|
||||
|
||||
By default `pip install` provides optimized binaries via [PyPI](https://pypi.org/project/pydantic/#files) for Linux, MacOS and 64bit Windows.
|
||||
|
||||
|
||||
+1
-1
@@ -90,7 +90,7 @@ To get started, all you need to do is create a `mypy.ini` file with following co
|
||||
plugins = pydantic.mypy
|
||||
```
|
||||
|
||||
The plugin is compatible with mypy versions `>=0.910`.
|
||||
The plugin is compatible with mypy versions `>=0.930`.
|
||||
|
||||
See the [mypy usage](usage/mypy.md) and [plugin configuration](#configuring-the-plugin) docs for more details.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
While pydantic will work well with any IDE out of the box, a
|
||||
While 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
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
autoflake==1.5.3
|
||||
ansi2html==1.8.0
|
||||
flake8==5.0.4
|
||||
flake8-quotes==3.3.1
|
||||
hypothesis==6.54.4
|
||||
markdown-include==0.7.0
|
||||
mdx-truly-sane-lists==1.3
|
||||
mkdocs==1.3.1
|
||||
mkdocs-exclude==1.0.2
|
||||
mkdocs-material==8.4.2
|
||||
pyupgrade==2.37.3
|
||||
sqlalchemy
|
||||
orjson
|
||||
ujson
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
!!! 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
|
||||
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.
|
||||
|
||||
@@ -112,12 +112,12 @@ not be included in the model schemas. **Note**: this means that attributes on th
|
||||
: whether to treat any underscore non-class var attrs as private, or leave them as is; see [Private model attributes](models.md#private-model-attributes)
|
||||
|
||||
**`copy_on_model_validation`**
|
||||
: string literal to control how models instances are processed during validation,
|
||||
: string literal to control how models instances are processed during validation,
|
||||
with the following means (see [#4093](https://github.com/pydantic/pydantic/pull/4093) for a full discussion of the changes to this field):
|
||||
|
||||
* `'none'` - models are not copied on validation, they're simply kept "untouched"
|
||||
* `'shallow'` - models are shallow copied, this is the default
|
||||
* `'deep'` - models are deep copied
|
||||
* `'deep'` - models are deep copied
|
||||
|
||||
**`smart_union`**
|
||||
: whether _pydantic_ should try to check all types inside `Union` to prevent undesired coercion; see [the dedicated section](#smart-union)
|
||||
|
||||
+30
-30
@@ -1,4 +1,4 @@
|
||||
The primary means of defining objects in *pydantic* is via models
|
||||
The primary means of defining objects in *pydantic* is via models
|
||||
(models are simply classes which inherit from `BaseModel`).
|
||||
|
||||
You can think of models as similar to types in strictly typed languages, or as the requirements of a single endpoint
|
||||
@@ -27,9 +27,9 @@ class User(BaseModel):
|
||||
id: int
|
||||
name = 'Jane Doe'
|
||||
```
|
||||
`User` here is a model with two fields `id` which is an integer and is required,
|
||||
`User` here is a model with two fields `id` which is an integer and is required,
|
||||
and `name` which is a string and is not required (it has a default value). The type of `name` is inferred from the
|
||||
default value, and so a type annotation is not required (however note [this](#field-ordering) warning about field
|
||||
default value, and so a type annotation is not required (however note [this](#field-ordering) warning about field
|
||||
order when some fields do not have type annotations).
|
||||
```py
|
||||
user = User(id='123')
|
||||
@@ -65,15 +65,15 @@ This model is mutable so field values can be changed.
|
||||
|
||||
### Model properties
|
||||
|
||||
The example above only shows the tip of the iceberg of what models can do.
|
||||
The example above only shows the tip of the iceberg of what models can do.
|
||||
Models possess the following methods and attributes:
|
||||
|
||||
`dict()`
|
||||
: returns a dictionary of the model's fields and values;
|
||||
: returns a dictionary of the model's fields and values;
|
||||
cf. [exporting models](exporting_models.md#modeldict)
|
||||
|
||||
`json()`
|
||||
: returns a JSON string representation `dict()`;
|
||||
: returns a JSON string representation `dict()`;
|
||||
cf. [exporting models](exporting_models.md#modeljson)
|
||||
|
||||
`copy()`
|
||||
@@ -99,7 +99,7 @@ Models possess the following methods and attributes:
|
||||
: returns a JSON string representation of `schema()`; cf. [schema](schema.md)
|
||||
|
||||
`construct()`
|
||||
: a class method for creating models without running validation;
|
||||
: a class method for creating models without running validation;
|
||||
cf. [Creating models without validation](#creating-models-without-validation)
|
||||
|
||||
`__fields_set__`
|
||||
@@ -159,7 +159,7 @@ Arbitrary classes are processed by *pydantic* using the `GetterDict` class (see
|
||||
provide a dictionary-like interface to any class. You can customise how this works by setting your own
|
||||
sub-class of `GetterDict` as the value of `Config.getter_dict` (see [config](model_config.md)).
|
||||
|
||||
You can also customise class validation using [root_validators](validators.md#root-validators) with `pre=True`.
|
||||
You can also customise class validation using [root_validators](validators.md#root-validators) with `pre=True`.
|
||||
In this case your validator function will be passed a `GetterDict` instance which you may copy and modify.
|
||||
|
||||
The `GetterDict` instance will be called for each field with a sentinel as a fallback (if no other default
|
||||
@@ -240,12 +240,12 @@ You can also define your own error classes, which can specify a custom error cod
|
||||
!!! warning
|
||||
To quote the [official `pickle` docs](https://docs.python.org/3/library/pickle.html),
|
||||
"The pickle module is not secure against erroneous or maliciously constructed data.
|
||||
Never unpickle data received from an untrusted or unauthenticated source."
|
||||
|
||||
Never unpickle data received from an untrusted or unauthenticated source."
|
||||
|
||||
!!! info
|
||||
Because it can result in arbitrary code execution, as a security measure, you need
|
||||
to explicitly pass `allow_pickle` to the parsing function in order to load `pickle` data.
|
||||
|
||||
|
||||
### Creating models without validation
|
||||
|
||||
*pydantic* also provides the `construct()` method which allows models to be created **without validation** this
|
||||
@@ -258,11 +258,11 @@ as efficiently as possible (`construct()` is generally around 30x faster than cr
|
||||
|
||||
{!.tmp_examples/models_construct.md!}
|
||||
|
||||
The `_fields_set` keyword argument to `construct()` is optional, but allows you to be more precise about
|
||||
The `_fields_set` keyword argument to `construct()` is optional, but allows you to be more precise about
|
||||
which fields were originally set and which weren't. If it's omitted `__fields_set__` will just be the keys
|
||||
of the data provided.
|
||||
of the data provided.
|
||||
|
||||
For example, in the example above, if `_fields_set` was not provided,
|
||||
For example, in the example above, if `_fields_set` was not provided,
|
||||
`new_user.__fields_set__` would be `{'id', 'age', 'name'}`.
|
||||
|
||||
## Generic Models
|
||||
@@ -292,12 +292,12 @@ you would expect mypy to provide if you were to declare the type without using `
|
||||
Internally, pydantic uses `create_model` to generate a (cached) concrete `BaseModel` at runtime,
|
||||
so there is essentially zero overhead introduced by making use of `GenericModel`.
|
||||
|
||||
To inherit from a GenericModel without replacing the `TypeVar` instance, a class must also inherit from
|
||||
To inherit from a GenericModel without replacing the `TypeVar` instance, a class must also inherit from
|
||||
`typing.Generic`:
|
||||
|
||||
{!.tmp_examples/models_generics_inheritance.md!}
|
||||
|
||||
You can also create a generic subclass of a `GenericModel` that partially or fully replaces the type
|
||||
You can also create a generic subclass of a `GenericModel` that partially or fully replaces the type
|
||||
parameters in the superclass.
|
||||
|
||||
{!.tmp_examples/models_generics_inheritance_extend.md!}
|
||||
@@ -311,7 +311,7 @@ Using the same TypeVar in nested models allows you to enforce typing relationshi
|
||||
{!.tmp_examples/models_generics_nested.md!}
|
||||
|
||||
Pydantic also treats `GenericModel` similarly to how it treats built-in generic types like `List` and `Dict` when it
|
||||
comes to leaving them unparameterized, or using bounded `TypeVar` instances:
|
||||
comes to leaving them unparameterized, or using bounded `TypeVar` instances:
|
||||
|
||||
* If you don't specify parameters before instantiating the generic model, they will be treated as `Any`
|
||||
* You can parametrize models with one or more *bounded* parameters to add subclass checks
|
||||
@@ -331,7 +331,7 @@ Here `StaticFoobarModel` and `DynamicFoobarModel` are identical.
|
||||
|
||||
!!! warning
|
||||
See the note in [Required Optional Fields](#required-optional-fields) for the distinction between an ellipsis as a
|
||||
field default and annotation-only fields.
|
||||
field default and annotation-only fields.
|
||||
See [pydantic/pydantic#1047](https://github.com/pydantic/pydantic/issues/1047) for more details.
|
||||
|
||||
Fields are defined by either a tuple of the form `(<type>, <default value>)` or just a default value. The
|
||||
@@ -356,7 +356,7 @@ Those methods have the exact same keyword arguments as `create_model`.
|
||||
|
||||
## Custom Root Types
|
||||
|
||||
Pydantic models can be defined with a custom root type by declaring the `__root__` field.
|
||||
Pydantic models can be defined with a custom root type by declaring the `__root__` field.
|
||||
|
||||
The root type can be any type supported by pydantic, and is specified by the type hint on the `__root__` field.
|
||||
The root value can be passed to the model `__init__` via the `__root__` keyword argument, or as
|
||||
@@ -371,7 +371,7 @@ the following logic is used:
|
||||
the argument itself is always validated against the custom root type.
|
||||
* For other custom root types, if the dict has precisely one key with the value `__root__`,
|
||||
the corresponding value will be validated against the custom root type.
|
||||
* Otherwise, the dict itself is validated against the custom root type.
|
||||
* Otherwise, the dict itself is validated against the custom root type.
|
||||
|
||||
This is demonstrated in the following example:
|
||||
|
||||
@@ -380,7 +380,7 @@ This is demonstrated in the following example:
|
||||
!!! warning
|
||||
Calling the `parse_obj` method on a dict with the single key `"__root__"` for non-mapping custom root types
|
||||
is currently supported for backwards compatibility, but is not recommended and may be dropped in a future version.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
{!.tmp_examples/models_custom_root_access.md!}
|
||||
@@ -410,7 +410,7 @@ Pydantic models can be used alongside Python's
|
||||
|
||||
Field order is important in models for the following reasons:
|
||||
|
||||
* validation is performed in the order fields are defined; [fields validators](validators.md)
|
||||
* validation is performed in the order fields are defined; [fields validators](validators.md)
|
||||
can access the values of earlier fields, but not later ones
|
||||
* field order is preserved in the model [schema](schema.md)
|
||||
* field order is preserved in [validation errors](#error-handling)
|
||||
@@ -430,7 +430,7 @@ all fields without an annotation. Within their respective groups, fields remain
|
||||
|
||||
## Required fields
|
||||
|
||||
To declare a field as required, you may declare it using just an annotation, or you may use an ellipsis (`...`)
|
||||
To declare a field as required, you may declare it using just an annotation, or you may use an ellipsis (`...`)
|
||||
as the value:
|
||||
|
||||
{!.tmp_examples/models_required_fields.md!}
|
||||
@@ -488,7 +488,7 @@ using `PrivateAttr`:
|
||||
|
||||
{!.tmp_examples/private_attributes.md!}
|
||||
|
||||
Private attribute names must start with underscore to prevent conflicts with model fields: both `_attr` and `__attr__`
|
||||
Private attribute names must start with underscore to prevent conflicts with model fields: both `_attr` and `__attr__`
|
||||
are supported.
|
||||
|
||||
If `Config.underscore_attrs_are_private` is `True`, any non-ClassVar underscore attribute will be treated as private:
|
||||
@@ -503,7 +503,7 @@ logic used to populate pydantic models in a more ad-hoc way. This function behav
|
||||
`BaseModel.parse_obj`, 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`.
|
||||
For example:
|
||||
For example:
|
||||
|
||||
{!.tmp_examples/parse_obj_as.md!}
|
||||
|
||||
@@ -520,7 +520,7 @@ For example:
|
||||
|
||||
{!.tmp_examples/models_data_conversion.md!}
|
||||
|
||||
This is a deliberate decision of *pydantic*, and in general it's the most useful approach. See
|
||||
This is a deliberate decision of *pydantic*, and in general it's the most useful approach. See
|
||||
[here](https://github.com/pydantic/pydantic/issues/578) for a longer discussion on the subject.
|
||||
|
||||
Nevertheless, [strict type checking](types.md#strict-types) is partially supported.
|
||||
@@ -537,14 +537,14 @@ The generated signature will also respect custom `__init__` functions:
|
||||
|
||||
{!.tmp_examples/models_signature_custom_init.md!}
|
||||
|
||||
To be included in the signature, a field's alias or name must be a valid Python identifier.
|
||||
*pydantic* prefers aliases over names, but may use field names if the alias is not a valid Python identifier.
|
||||
To be included in the signature, a field's alias or name must be a valid Python identifier.
|
||||
*pydantic* prefers aliases over names, but may use field names if the alias is not a valid Python identifier.
|
||||
|
||||
If a field's alias and name are both invalid identifiers, a `**data` argument will be added.
|
||||
In addition, the `**data` argument will always be present in the signature if `Config.extra` is `Extra.allow`.
|
||||
|
||||
!!! note
|
||||
Types in the model signature are the same as declared in model annotations,
|
||||
Types in the model signature are the same as declared in model annotations,
|
||||
not necessarily all the types that can actually be provided to that field.
|
||||
This may be fixed one day once [#1055](https://github.com/pydantic/pydantic/issues/1055) is solved.
|
||||
|
||||
@@ -555,5 +555,5 @@ In addition, the `**data` argument will always be present in the signature if `C
|
||||
{!.tmp_examples/models_structural_pattern_matching.md!}
|
||||
|
||||
!!! note
|
||||
A match-case statement may seem as if it creates a new model, but don't be fooled;
|
||||
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.
|
||||
|
||||
+2
-1
@@ -619,7 +619,7 @@ For URI/URL validation the following types are available:
|
||||
|
||||
!!! warning
|
||||
In V1.10.0 and v1.10.1 `stricturl` also took an optional `quote_plus` argument and URL components were percent
|
||||
encoded in some cases. This feature was removed in v1.10.2, see
|
||||
encoded in some cases. This feature was removed in v1.10.2, see
|
||||
[#4470](https://github.com/pydantic/pydantic/pull/4470) for explanation and more details.
|
||||
|
||||
The above types (which all inherit from `AnyUrl`) will attempt to give descriptive errors when invalid URLs are
|
||||
@@ -683,6 +683,7 @@ If further validation is required, these properties can be used by validators to
|
||||
Also, Chrome, Firefox, and Safari all currently accept `http://exam_ple.com` as a URL, so we're in good
|
||||
(or at least big) company.
|
||||
|
||||
|
||||
### Color Type
|
||||
|
||||
You can use the `Color` data type for storing colors as per
|
||||
|
||||
@@ -251,15 +251,15 @@ 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
|
||||
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".
|
||||
|
||||

|
||||
|
||||
## BaseSettings and ignoring Pylance/pyright errors
|
||||
|
||||
Pylance/pyright does not work well with [`BaseSettings`](./usage/settings.md) - fields in settings classes can be
|
||||
Pylance/pyright does not work well with [`BaseSettings`](./usage/settings.md) - fields in settings classes can be
|
||||
configured via environment variables and therefore "required" fields do not have to be explicitly set when
|
||||
initialising a settings instance. However, pyright considers these fields as "required" and will therefore
|
||||
show an error when they're not set.
|
||||
@@ -284,7 +284,7 @@ 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"
|
||||
lance = Knight() # error: Argument missing for parameter "age"
|
||||
```
|
||||
|
||||
Like the issue with `BaseSettings`, this is a limitation of dataclass transforms and cannot be fixed in pydantic.
|
||||
|
||||
+1
-1
@@ -81,7 +81,7 @@ markdown_extensions:
|
||||
emoji_index: !!python/name:materialx.emoji.twemoji
|
||||
emoji_generator: !!python/name:materialx.emoji.to_svg
|
||||
- pymdownx.tabbed:
|
||||
alternate_style: true
|
||||
alternate_style: true
|
||||
|
||||
plugins:
|
||||
- search
|
||||
|
||||
@@ -13,7 +13,7 @@ from .networks import *
|
||||
from .parse import Protocol
|
||||
from .tools import *
|
||||
from .types import *
|
||||
from .version import VERSION, compiled
|
||||
from .version import VERSION
|
||||
|
||||
__version__ = VERSION
|
||||
|
||||
@@ -126,6 +126,5 @@ __all__ = [
|
||||
'PastDate',
|
||||
'FutureDate',
|
||||
# version
|
||||
'compiled',
|
||||
'VERSION',
|
||||
]
|
||||
|
||||
+29
-41
@@ -2,11 +2,10 @@ import json
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING, Any, Callable, Dict, ForwardRef, Optional, Tuple, Type, Union
|
||||
|
||||
from typing_extensions import Literal, Protocol
|
||||
from typing_extensions import Literal, Protocol, TypedDict
|
||||
|
||||
from .typing import AnyArgTCallable, AnyCallable
|
||||
from .utils import GetterDict
|
||||
from .version import compiled
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import overload
|
||||
@@ -37,45 +36,34 @@ class Extra(str, Enum):
|
||||
forbid = 'forbid'
|
||||
|
||||
|
||||
# https://github.com/cython/cython/issues/4003
|
||||
# Will be fixed with Cython 3 but still in alpha right now
|
||||
if not compiled:
|
||||
from typing_extensions import TypedDict
|
||||
|
||||
class ConfigDict(TypedDict, total=False):
|
||||
title: Optional[str]
|
||||
anystr_lower: bool
|
||||
anystr_strip_whitespace: bool
|
||||
min_anystr_length: int
|
||||
max_anystr_length: Optional[int]
|
||||
validate_all: bool
|
||||
extra: Extra
|
||||
allow_mutation: bool
|
||||
frozen: bool
|
||||
allow_population_by_field_name: bool
|
||||
use_enum_values: bool
|
||||
fields: Dict[str, Union[str, Dict[str, str]]]
|
||||
validate_assignment: bool
|
||||
error_msg_templates: Dict[str, str]
|
||||
arbitrary_types_allowed: bool
|
||||
orm_mode: bool
|
||||
getter_dict: Type[GetterDict]
|
||||
alias_generator: Optional[Callable[[str], str]]
|
||||
keep_untouched: Tuple[type, ...]
|
||||
schema_extra: Union[Dict[str, object], 'SchemaExtraCallable']
|
||||
json_loads: Callable[[str], object]
|
||||
json_dumps: AnyArgTCallable[str]
|
||||
json_encoders: Dict[Type[object], AnyCallable]
|
||||
underscore_attrs_are_private: bool
|
||||
allow_inf_nan: bool
|
||||
|
||||
# whether or not inherited models as fields should be reconstructed as base model
|
||||
copy_on_model_validation: bool
|
||||
# whether dataclass `__post_init__` should be run after validation
|
||||
post_init_call: Literal['before_validation', 'after_validation']
|
||||
|
||||
else:
|
||||
ConfigDict = dict # type: ignore
|
||||
class ConfigDict(TypedDict, total=False):
|
||||
title: Optional[str]
|
||||
anystr_lower: bool
|
||||
anystr_strip_whitespace: bool
|
||||
min_anystr_length: int
|
||||
max_anystr_length: Optional[int]
|
||||
validate_all: bool
|
||||
extra: Extra
|
||||
allow_mutation: bool
|
||||
frozen: bool
|
||||
allow_population_by_field_name: bool
|
||||
use_enum_values: bool
|
||||
fields: Dict[str, Union[str, Dict[str, str]]]
|
||||
validate_assignment: bool
|
||||
error_msg_templates: Dict[str, str]
|
||||
arbitrary_types_allowed: bool
|
||||
orm_mode: bool
|
||||
getter_dict: Type[GetterDict]
|
||||
alias_generator: Optional[Callable[[str], str]]
|
||||
keep_untouched: Tuple[type, ...]
|
||||
schema_extra: Union[Dict[str, object], 'SchemaExtraCallable']
|
||||
json_loads: Callable[[str], object]
|
||||
json_dumps: AnyArgTCallable[str]
|
||||
json_encoders: Dict[Type[object], AnyCallable]
|
||||
underscore_attrs_are_private: bool
|
||||
allow_inf_nan: bool
|
||||
copy_on_model_validation: Literal['none', 'deep', 'shallow']
|
||||
post_init_call: Literal['before_validation', 'after_validation']
|
||||
|
||||
|
||||
class BaseConfig:
|
||||
|
||||
@@ -204,7 +204,7 @@ def dataclass(
|
||||
else:
|
||||
dc_cls_doc = cls.__doc__ or '' # needs to be done before generating dataclass
|
||||
if sys.version_info >= (3, 10):
|
||||
dc_cls = dataclasses.dataclass(
|
||||
dc_cls = dataclasses.dataclass( # type: ignore[call-overload]
|
||||
cls,
|
||||
init=init,
|
||||
repr=repr,
|
||||
@@ -215,7 +215,7 @@ def dataclass(
|
||||
kw_only=kw_only,
|
||||
)
|
||||
else:
|
||||
dc_cls = dataclasses.dataclass( # type: ignore
|
||||
dc_cls = dataclasses.dataclass(
|
||||
cls, init=init, repr=repr, eq=eq, order=order, unsafe_hash=unsafe_hash, frozen=frozen
|
||||
)
|
||||
default_validate_on_init = True
|
||||
|
||||
+11
-26
@@ -68,7 +68,7 @@ from pydantic.utils import is_valid_field
|
||||
try:
|
||||
from mypy.types import TypeVarDef # type: ignore[attr-defined]
|
||||
except ImportError: # pragma: no cover
|
||||
# Backward-compatible with TypeVarDef from Mypy 0.910.
|
||||
# Backward-compatible with TypeVarDef from Mypy 0.930.
|
||||
from mypy.types import TypeVarType as TypeVarDef
|
||||
|
||||
CONFIGFILE_KEY = 'pydantic-mypy'
|
||||
@@ -164,11 +164,7 @@ class PydanticPlugin(Plugin):
|
||||
# Functions which use `ParamSpec` can be overloaded, exposing the callable's types as a parameter
|
||||
# Pydantic calls the default factory without any argument, so we retrieve the first item
|
||||
if isinstance(default_factory_type, Overloaded):
|
||||
if MYPY_VERSION_TUPLE > (0, 910):
|
||||
default_factory_type = default_factory_type.items[0]
|
||||
else:
|
||||
# Mypy0.910 exposes the items of overloaded types in a function
|
||||
default_factory_type = default_factory_type.items()[0] # type: ignore[operator]
|
||||
default_factory_type = default_factory_type.items[0]
|
||||
|
||||
if isinstance(default_factory_type, CallableType):
|
||||
ret_type = default_factory_type.ret_type
|
||||
@@ -448,23 +444,18 @@ class PydanticModelTransformer:
|
||||
obj_type = ctx.api.named_type(f'{BUILTINS_NAME}.object')
|
||||
self_tvar_name = '_PydanticBaseModel' # Make sure it does not conflict with other names in the class
|
||||
tvar_fullname = ctx.cls.fullname + '.' + self_tvar_name
|
||||
tvd = TypeVarDef(self_tvar_name, tvar_fullname, -1, [], obj_type)
|
||||
# requires mypy>0.910
|
||||
self_type = TypeVarDef(self_tvar_name, tvar_fullname, -1, [], obj_type)
|
||||
self_tvar_expr = TypeVarExpr(self_tvar_name, tvar_fullname, [], obj_type)
|
||||
ctx.cls.info.names[self_tvar_name] = SymbolTableNode(MDEF, self_tvar_expr)
|
||||
|
||||
# Backward-compatible with TypeVarDef from Mypy 0.910.
|
||||
if isinstance(tvd, TypeVarType):
|
||||
self_type = tvd
|
||||
else:
|
||||
self_type = TypeVarType(tvd) # type: ignore[call-arg]
|
||||
|
||||
add_method(
|
||||
ctx,
|
||||
'construct',
|
||||
construct_arguments,
|
||||
return_type=self_type,
|
||||
self_type=self_type,
|
||||
tvar_def=tvd,
|
||||
tvar_def=self_type,
|
||||
is_classmethod=True,
|
||||
)
|
||||
|
||||
@@ -829,22 +820,16 @@ def parse_toml(config_file: str) -> Optional[Dict[str, Any]]:
|
||||
if not config_file.endswith('.toml'):
|
||||
return None
|
||||
|
||||
read_mode = 'rb'
|
||||
if sys.version_info >= (3, 11):
|
||||
import tomllib as toml_
|
||||
else:
|
||||
try:
|
||||
import tomli as toml_
|
||||
except ImportError:
|
||||
# older versions of mypy have toml as a dependency, not tomli
|
||||
read_mode = 'r'
|
||||
try:
|
||||
import toml as toml_ # type: ignore[no-redef]
|
||||
except ImportError: # pragma: no cover
|
||||
import warnings
|
||||
except ImportError: # pragma: no cover
|
||||
import warnings
|
||||
|
||||
warnings.warn('No TOML parser installed, cannot read configuration from `pyproject.toml`.')
|
||||
return None
|
||||
warnings.warn('No TOML parser installed, cannot read configuration from `pyproject.toml`.')
|
||||
return None
|
||||
|
||||
with open(config_file, read_mode) as rf:
|
||||
return toml_.load(rf) # type: ignore[arg-type]
|
||||
with open(config_file, 'rb') as rf:
|
||||
return toml_.load(rf)
|
||||
|
||||
+3
-3
@@ -46,10 +46,10 @@ except ImportError:
|
||||
TypingGenericAlias = ()
|
||||
|
||||
try:
|
||||
from types import UnionType as TypesUnionType # type: ignore
|
||||
from types import UnionType as TypesUnionType
|
||||
except ImportError:
|
||||
# python < 3.10 does not have UnionType (str | int, byte | bool and so on)
|
||||
TypesUnionType = ()
|
||||
TypesUnionType = () # type: ignore[misc,assignment]
|
||||
|
||||
|
||||
if sys.version_info < (3, 9):
|
||||
@@ -243,7 +243,7 @@ else:
|
||||
def is_union(tp: Optional[Type[Any]]) -> bool:
|
||||
return tp is Union or tp is types.UnionType # noqa: E721
|
||||
|
||||
WithArgsTypes = (typing._GenericAlias, types.GenericAlias, types.UnionType)
|
||||
WithArgsTypes = (typing._GenericAlias, types.GenericAlias, types.UnionType) # type: ignore[attr-defined]
|
||||
|
||||
|
||||
if sys.version_info < (3, 9):
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import keyword
|
||||
import warnings
|
||||
import weakref
|
||||
from collections import OrderedDict, defaultdict, deque
|
||||
from copy import deepcopy
|
||||
@@ -139,23 +138,6 @@ def import_string(dotted_path: str) -> Any:
|
||||
raise ImportError(f'Module "{module_path}" does not define a "{class_name}" attribute') from e
|
||||
|
||||
|
||||
def truncate(v: Union[str], *, max_len: int = 80) -> str:
|
||||
"""
|
||||
Truncate a value and add a unicode ellipsis (three dots) to the end if it was too long
|
||||
"""
|
||||
warnings.warn('`truncate` is no-longer used by pydantic and is deprecated', DeprecationWarning)
|
||||
if isinstance(v, str) and len(v) > (max_len - 2):
|
||||
# -3 so quote + string + … + quote has correct length
|
||||
return (v[: (max_len - 3)] + '…').__repr__()
|
||||
try:
|
||||
v = v.__repr__()
|
||||
except TypeError:
|
||||
v = v.__class__.__repr__(v) # in case v is a type
|
||||
if len(v) > max_len:
|
||||
v = v[: max_len - 1] + '…'
|
||||
return v
|
||||
|
||||
|
||||
def sequence_like(v: Any) -> bool:
|
||||
return isinstance(v, (list, tuple, set, frozenset, GeneratorType, deque))
|
||||
|
||||
|
||||
+2
-13
@@ -1,16 +1,6 @@
|
||||
__all__ = 'compiled', 'VERSION', 'version_info'
|
||||
__all__ = 'VERSION', 'version_info'
|
||||
|
||||
VERSION = '1.10.2'
|
||||
|
||||
try:
|
||||
import cython # type: ignore
|
||||
except ImportError:
|
||||
compiled: bool = False
|
||||
else: # pragma: no cover
|
||||
try:
|
||||
compiled = cython.compiled
|
||||
except AttributeError:
|
||||
compiled = False
|
||||
VERSION = '2.0.0.dev0'
|
||||
|
||||
|
||||
def version_info() -> str:
|
||||
@@ -29,7 +19,6 @@ def version_info() -> str:
|
||||
|
||||
info = {
|
||||
'pydantic version': VERSION,
|
||||
'pydantic compiled': compiled,
|
||||
'install path': Path(__file__).resolve().parent,
|
||||
'python version': sys.version,
|
||||
'platform': platform.platform(),
|
||||
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
[build-system]
|
||||
requires = ['hatchling']
|
||||
build-backend = 'hatchling.build'
|
||||
|
||||
[tool.hatch.version]
|
||||
path = 'pydantic/version.py'
|
||||
|
||||
[project]
|
||||
name = 'pydantic'
|
||||
description = 'Data validation using Python type hints'
|
||||
authors = [
|
||||
{name = 'Samuel Colvin', email = 's@muelcolvin.com'},
|
||||
{name = 'Eric Jolibois', email = 'em.jolibois@gmail.com'},
|
||||
{name = 'Hasan Ramezani', email = 'hasan.r67@gmail.com'},
|
||||
]
|
||||
license = {file = 'LICENSE'}
|
||||
readme = 'README.md'
|
||||
classifiers = [
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3 :: Only',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Programming Language :: Python :: 3.9',
|
||||
'Programming Language :: Python :: 3.10',
|
||||
'Programming Language :: Python :: 3.11',
|
||||
'Intended Audience :: Developers',
|
||||
'Intended Audience :: Information Technology',
|
||||
'Intended Audience :: System Administrators',
|
||||
'License :: OSI Approved :: MIT License',
|
||||
'Operating System :: Unix',
|
||||
'Operating System :: POSIX :: Linux',
|
||||
'Environment :: Console',
|
||||
'Environment :: MacOS X',
|
||||
'Framework :: Hypothesis',
|
||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||
'Topic :: Internet',
|
||||
]
|
||||
requires-python = '>=3.7'
|
||||
dependencies = [ 'typing-extensions>=4.1.0' ]
|
||||
optional-dependencies = { email = ['email-validator>=1.0.3'], dotenv = ['python-dotenv>=0.10.4'] }
|
||||
dynamic = ['version']
|
||||
|
||||
entry-points.hypothesis = {_ = 'pydantic._hypothesis_plugin'}
|
||||
|
||||
[project.urls]
|
||||
Homepage = 'https://github.com/pydantic/pydantic'
|
||||
Documentation = 'https://pydantic-docs.helpmanual.io'
|
||||
Funding = 'https://github.com/sponsors/samuelcolvin'
|
||||
Source = 'https://github.com/pydantic/pydantic'
|
||||
Changelog = 'https://pydantic-docs.helpmanual.io/changelog'
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = 'tests'
|
||||
filterwarnings = [
|
||||
'error',
|
||||
'ignore:path is deprecated.*:DeprecationWarning:certifi',
|
||||
]
|
||||
|
||||
[tool.flake8]
|
||||
max_line_length = 120
|
||||
max_complexity = 14
|
||||
inline_quotes = 'single'
|
||||
multiline_quotes = 'double'
|
||||
ignore = ['E203', 'W503']
|
||||
per_file_ignores = [
|
||||
'docs/examples/schema_unenforced_constraints.py:F811',
|
||||
'docs/examples/validation_decorator_async.py:E402',
|
||||
'docs/examples/types_constrained.py:F722',
|
||||
]
|
||||
|
||||
[tool.coverage.run]
|
||||
source = ['pydantic']
|
||||
branch = true
|
||||
context = '${CONTEXT}'
|
||||
|
||||
[tool.coverage.report]
|
||||
precision = 2
|
||||
exclude_lines = [
|
||||
'pragma: no cover',
|
||||
'raise NotImplementedError',
|
||||
'raise NotImplemented',
|
||||
'if TYPE_CHECKING:',
|
||||
'@overload',
|
||||
]
|
||||
|
||||
|
||||
[tool.coverage.paths]
|
||||
source = [
|
||||
'pydantic/',
|
||||
'/Users/runner/work/pydantic/pydantic/pydantic/',
|
||||
'D:\a\pydantic\pydantic\pydantic',
|
||||
]
|
||||
|
||||
[tool.black]
|
||||
color = true
|
||||
line-length = 120
|
||||
target-version = ['py310']
|
||||
skip-string-normalization = true
|
||||
|
||||
[tool.isort]
|
||||
line_length = 120
|
||||
known_first_party = 'pydantic'
|
||||
multi_line_output = 3
|
||||
include_trailing_comma = true
|
||||
force_grid_wrap = 0
|
||||
combine_as_imports = true
|
||||
|
||||
[tool.mypy]
|
||||
python_version = '3.10'
|
||||
show_error_codes = true
|
||||
follow_imports = 'silent'
|
||||
strict_optional = true
|
||||
warn_redundant_casts = true
|
||||
warn_unused_ignores = true
|
||||
disallow_any_generics = true
|
||||
check_untyped_defs = true
|
||||
no_implicit_reexport = true
|
||||
warn_unused_configs = true
|
||||
disallow_subclassing_any = true
|
||||
disallow_incomplete_defs = true
|
||||
disallow_untyped_decorators = true
|
||||
disallow_untyped_calls = true
|
||||
|
||||
# for strict mypy: (this is the tricky one :-))
|
||||
disallow_untyped_defs = true
|
||||
|
||||
# remaining arguments from `mypy --strict` which cause errors
|
||||
# no_implicit_optional = true
|
||||
# warn_return_any = true
|
||||
|
||||
# ansi2html and devtools are required to avoid the need to install these packages when running linting,
|
||||
# they're used in the docs build script
|
||||
[[tool.mypy.overrides]]
|
||||
module = [
|
||||
'email_validator.*',
|
||||
'dotenv.*',
|
||||
'toml.*',
|
||||
'ansi2html.*',
|
||||
'devtools.*',
|
||||
]
|
||||
ignore_missing_imports = true
|
||||
@@ -1,8 +0,0 @@
|
||||
# requirements for compilation and from setup.py so dependabot prompts us to test with latest version of these packages
|
||||
|
||||
Cython==0.29.32;sys_platform!='win32'
|
||||
devtools==0.9.0
|
||||
email-validator==1.2.1
|
||||
dataclasses==0.6; python_version < '3.7'
|
||||
typing-extensions==4.3.0
|
||||
python-dotenv==0.20.0
|
||||
@@ -0,0 +1,5 @@
|
||||
-r ./pyproject-all.txt
|
||||
-r ./docs.txt
|
||||
-r ./linting.txt
|
||||
-r ./testing.txt
|
||||
-r ./testing-extra.txt
|
||||
@@ -0,0 +1,16 @@
|
||||
autoflake
|
||||
ansi2html
|
||||
devtools
|
||||
flake8
|
||||
flake8-quotes
|
||||
flake8-pyproject
|
||||
hypothesis
|
||||
markdown-include
|
||||
mdx-truly-sane-lists
|
||||
mkdocs
|
||||
mkdocs-exclude
|
||||
mkdocs-material
|
||||
pyupgrade
|
||||
orjson
|
||||
sqlalchemy
|
||||
ujson
|
||||
@@ -0,0 +1,119 @@
|
||||
#
|
||||
# This file is autogenerated by pip-compile with python 3.10
|
||||
# To update, run:
|
||||
#
|
||||
# pip-compile --output-file=requirements/docs.txt requirements/docs.in
|
||||
#
|
||||
ansi2html==1.8.0
|
||||
# via -r requirements/docs.in
|
||||
asttokens==2.0.8
|
||||
# via devtools
|
||||
attrs==22.1.0
|
||||
# via hypothesis
|
||||
autoflake==1.5.3
|
||||
# via -r requirements/docs.in
|
||||
click==8.1.3
|
||||
# via mkdocs
|
||||
devtools==0.9.0
|
||||
# via -r requirements/docs.in
|
||||
exceptiongroup==1.0.0rc9
|
||||
# via hypothesis
|
||||
executing==0.10.0
|
||||
# via devtools
|
||||
flake8==5.0.4
|
||||
# via
|
||||
# -r requirements/docs.in
|
||||
# flake8-pyproject
|
||||
# flake8-quotes
|
||||
flake8-pyproject==1.1.0.post0
|
||||
# via -r requirements/docs.in
|
||||
flake8-quotes==3.3.1
|
||||
# via -r requirements/docs.in
|
||||
ghp-import==2.1.0
|
||||
# via mkdocs
|
||||
greenlet==1.1.3
|
||||
# via sqlalchemy
|
||||
hypothesis==6.54.4
|
||||
# via -r requirements/docs.in
|
||||
importlib-metadata==4.12.0
|
||||
# via mkdocs
|
||||
jinja2==3.1.2
|
||||
# via
|
||||
# mkdocs
|
||||
# mkdocs-material
|
||||
markdown==3.3.7
|
||||
# via
|
||||
# markdown-include
|
||||
# mdx-truly-sane-lists
|
||||
# mkdocs
|
||||
# mkdocs-material
|
||||
# pymdown-extensions
|
||||
markdown-include==0.7.0
|
||||
# via -r requirements/docs.in
|
||||
markupsafe==2.1.1
|
||||
# via jinja2
|
||||
mccabe==0.7.0
|
||||
# via flake8
|
||||
mdx-truly-sane-lists==1.3
|
||||
# via -r requirements/docs.in
|
||||
mergedeep==1.3.4
|
||||
# via mkdocs
|
||||
mkdocs==1.3.1
|
||||
# via
|
||||
# -r requirements/docs.in
|
||||
# mkdocs-exclude
|
||||
# mkdocs-material
|
||||
mkdocs-exclude==1.0.2
|
||||
# via -r requirements/docs.in
|
||||
mkdocs-material==8.4.2
|
||||
# via -r requirements/docs.in
|
||||
mkdocs-material-extensions==1.0.3
|
||||
# via mkdocs-material
|
||||
orjson==3.8.0
|
||||
# via -r requirements/docs.in
|
||||
packaging==21.3
|
||||
# via mkdocs
|
||||
pycodestyle==2.9.1
|
||||
# via flake8
|
||||
pyflakes==2.5.0
|
||||
# via
|
||||
# autoflake
|
||||
# flake8
|
||||
pygments==2.13.0
|
||||
# via mkdocs-material
|
||||
pymdown-extensions==9.5
|
||||
# via mkdocs-material
|
||||
pyparsing==3.0.9
|
||||
# via packaging
|
||||
python-dateutil==2.8.2
|
||||
# via ghp-import
|
||||
pyupgrade==2.37.3
|
||||
# via -r requirements/docs.in
|
||||
pyyaml==6.0
|
||||
# via
|
||||
# mkdocs
|
||||
# pyyaml-env-tag
|
||||
pyyaml-env-tag==0.1
|
||||
# via mkdocs
|
||||
six==1.16.0
|
||||
# via
|
||||
# asttokens
|
||||
# python-dateutil
|
||||
sortedcontainers==2.4.0
|
||||
# via hypothesis
|
||||
sqlalchemy==1.4.40
|
||||
# via -r requirements/docs.in
|
||||
tokenize-rt==4.2.1
|
||||
# via pyupgrade
|
||||
toml==0.10.2
|
||||
# via autoflake
|
||||
tomli==2.0.1
|
||||
# via flake8-pyproject
|
||||
typing-extensions==4.3.0
|
||||
# via -r requirements/docs.in
|
||||
ujson==5.4.0
|
||||
# via -r requirements/docs.in
|
||||
watchdog==2.1.9
|
||||
# via mkdocs
|
||||
zipp==3.8.1
|
||||
# via importlib-metadata
|
||||
@@ -0,0 +1,9 @@
|
||||
black
|
||||
flake8
|
||||
flake8-quotes
|
||||
flake8-pyproject
|
||||
hypothesis
|
||||
isort
|
||||
pyupgrade
|
||||
mypy
|
||||
pre-commit
|
||||
@@ -0,0 +1,79 @@
|
||||
#
|
||||
# This file is autogenerated by pip-compile with python 3.10
|
||||
# To update, run:
|
||||
#
|
||||
# pip-compile --output-file=requirements/linting.txt requirements/linting.in
|
||||
#
|
||||
attrs==22.1.0
|
||||
# via hypothesis
|
||||
black==22.8.0
|
||||
# via -r requirements/linting.in
|
||||
cfgv==3.3.1
|
||||
# via pre-commit
|
||||
click==8.1.3
|
||||
# via black
|
||||
distlib==0.3.6
|
||||
# via virtualenv
|
||||
exceptiongroup==1.0.0rc9
|
||||
# via hypothesis
|
||||
filelock==3.8.0
|
||||
# via virtualenv
|
||||
flake8==5.0.4
|
||||
# via
|
||||
# -r requirements/linting.in
|
||||
# flake8-pyproject
|
||||
# flake8-quotes
|
||||
flake8-pyproject==1.1.0.post0
|
||||
# via -r requirements/linting.in
|
||||
flake8-quotes==3.3.1
|
||||
# via -r requirements/linting.in
|
||||
hypothesis==6.54.4
|
||||
# via -r requirements/linting.in
|
||||
identify==2.5.3
|
||||
# via pre-commit
|
||||
isort==5.10.1
|
||||
# via -r requirements/linting.in
|
||||
mccabe==0.7.0
|
||||
# via flake8
|
||||
mypy==0.971
|
||||
# via -r requirements/linting.in
|
||||
mypy-extensions==0.4.3
|
||||
# via
|
||||
# black
|
||||
# mypy
|
||||
nodeenv==1.7.0
|
||||
# via pre-commit
|
||||
pathspec==0.10.1
|
||||
# via black
|
||||
platformdirs==2.5.2
|
||||
# via
|
||||
# black
|
||||
# virtualenv
|
||||
pre-commit==2.20.0
|
||||
# via -r requirements/linting.in
|
||||
pycodestyle==2.9.1
|
||||
# via flake8
|
||||
pyflakes==2.5.0
|
||||
# via flake8
|
||||
pyupgrade==2.37.3
|
||||
# via -r requirements/linting.in
|
||||
pyyaml==6.0
|
||||
# via pre-commit
|
||||
sortedcontainers==2.4.0
|
||||
# via hypothesis
|
||||
tokenize-rt==4.2.1
|
||||
# via pyupgrade
|
||||
toml==0.10.2
|
||||
# via pre-commit
|
||||
tomli==2.0.1
|
||||
# via
|
||||
# black
|
||||
# flake8-pyproject
|
||||
# mypy
|
||||
typing-extensions==4.3.0
|
||||
# via mypy
|
||||
virtualenv==20.16.4
|
||||
# via pre-commit
|
||||
|
||||
# The following packages are considered to be unsafe in a requirements file:
|
||||
# setuptools
|
||||
@@ -0,0 +1,16 @@
|
||||
#
|
||||
# This file is autogenerated by pip-compile with python 3.10
|
||||
# To update, run:
|
||||
#
|
||||
# pip-compile --extra=email,dotenv --output-file=requirements/pyproject-all.txt pyproject.toml
|
||||
#
|
||||
dnspython==2.2.1
|
||||
# via email-validator
|
||||
email-validator==1.2.1
|
||||
# via pydantic (pyproject.toml)
|
||||
idna==3.3
|
||||
# via email-validator
|
||||
python-dotenv==0.20.0
|
||||
# via pydantic (pyproject.toml)
|
||||
typing-extensions==4.3.0
|
||||
# via pydantic (pyproject.toml)
|
||||
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# This file is autogenerated by pip-compile with python 3.10
|
||||
# To update, run:
|
||||
#
|
||||
# pip-compile --output-file=requirements/pyproject-min.txt pyproject.toml
|
||||
#
|
||||
typing-extensions==4.3.0
|
||||
# via pydantic (pyproject.toml)
|
||||
@@ -0,0 +1,4 @@
|
||||
devtools
|
||||
hypothesis
|
||||
mypy
|
||||
typed-ast;python_version<'3.8'
|
||||
@@ -0,0 +1,34 @@
|
||||
#
|
||||
# This file is autogenerated by pip-compile with python 3.7
|
||||
# To update, run:
|
||||
#
|
||||
# pip-compile --output-file=requirements/testing-extra.txt requirements/testing-extra.in
|
||||
#
|
||||
asttokens==2.0.8
|
||||
# via devtools
|
||||
attrs==22.1.0
|
||||
# via hypothesis
|
||||
devtools==0.9.0
|
||||
# via -r requirements/testing-extra.in
|
||||
exceptiongroup==1.0.0rc9
|
||||
# via hypothesis
|
||||
executing==0.10.0
|
||||
# via devtools
|
||||
hypothesis==6.54.4
|
||||
# via -r requirements/testing-extra.in
|
||||
mypy==0.971
|
||||
# via -r requirements/testing-extra.in
|
||||
mypy-extensions==0.4.3
|
||||
# via mypy
|
||||
six==1.16.0
|
||||
# via asttokens
|
||||
sortedcontainers==2.4.0
|
||||
# via hypothesis
|
||||
tomli==2.0.1
|
||||
# via mypy
|
||||
typed-ast==1.5.4 ; python_version < "3.8"
|
||||
# via
|
||||
# -r requirements/testing-extra.in
|
||||
# mypy
|
||||
typing-extensions==4.3.0
|
||||
# via mypy
|
||||
@@ -0,0 +1,4 @@
|
||||
coverage[toml]
|
||||
pytest
|
||||
pytest-mock
|
||||
pytest-sugar
|
||||
@@ -0,0 +1,45 @@
|
||||
#
|
||||
# This file is autogenerated by pip-compile with python 3.7
|
||||
# To update, run:
|
||||
#
|
||||
# pip-compile --output-file=requirements/testing.txt requirements/testing.in
|
||||
#
|
||||
attrs==22.1.0
|
||||
# via pytest
|
||||
coverage[toml]==6.4.4
|
||||
# via -r requirements/testing.in
|
||||
importlib-metadata==4.12.0
|
||||
# via
|
||||
# pluggy
|
||||
# pytest
|
||||
iniconfig==1.1.1
|
||||
# via pytest
|
||||
packaging==21.3
|
||||
# via
|
||||
# pytest
|
||||
# pytest-sugar
|
||||
pluggy==1.0.0
|
||||
# via pytest
|
||||
py==1.11.0
|
||||
# via pytest
|
||||
pyparsing==3.0.9
|
||||
# via packaging
|
||||
pytest==7.1.3
|
||||
# via
|
||||
# -r requirements/testing.in
|
||||
# pytest-mock
|
||||
# pytest-sugar
|
||||
pytest-mock==3.8.2
|
||||
# via -r requirements/testing.in
|
||||
pytest-sugar==0.9.5
|
||||
# via -r requirements/testing.in
|
||||
termcolor==1.1.0
|
||||
# via pytest-sugar
|
||||
tomli==2.0.1
|
||||
# via
|
||||
# coverage
|
||||
# pytest
|
||||
typing-extensions==4.3.0
|
||||
# via importlib-metadata
|
||||
zipp==3.8.1
|
||||
# via importlib-metadata
|
||||
@@ -1,92 +0,0 @@
|
||||
[tool:pytest]
|
||||
testpaths = tests
|
||||
addopts = -p no:hypothesispytest
|
||||
filterwarnings =
|
||||
error
|
||||
ignore::DeprecationWarning:distutils
|
||||
ignore::DeprecationWarning:Cython
|
||||
# for Python 3.10+: mypy still relies on distutils on windows. We hence ignore those warnings
|
||||
ignore:The distutils package is deprecated and slated for removal in Python 3.12:DeprecationWarning
|
||||
ignore:The distutils.sysconfig module is deprecated, use sysconfig instead:DeprecationWarning
|
||||
# for Python 3.11
|
||||
ignore:path is deprecated.*:DeprecationWarning:certifi
|
||||
ignore:module 'sre_constants' is deprecated:DeprecationWarning:pkg_resources
|
||||
|
||||
[flake8]
|
||||
max-line-length = 120
|
||||
max-complexity = 14
|
||||
inline-quotes = single
|
||||
multiline-quotes = double
|
||||
ignore = E203, W503
|
||||
per-file-ignores =
|
||||
docs/examples/schema_unenforced_constraints.py: F811
|
||||
docs/examples/validation_decorator_async.py: E402
|
||||
docs/examples/types_constrained.py: F722
|
||||
|
||||
[coverage:run]
|
||||
source = pydantic
|
||||
branch = True
|
||||
context = ${CONTEXT}
|
||||
|
||||
[coverage:report]
|
||||
precision = 2
|
||||
exclude_lines =
|
||||
pragma: no cover
|
||||
raise NotImplementedError
|
||||
raise NotImplemented
|
||||
if TYPE_CHECKING:
|
||||
@overload
|
||||
|
||||
[coverage:paths]
|
||||
source =
|
||||
pydantic/
|
||||
/Users/runner/work/pydantic/pydantic/pydantic/
|
||||
D:\a\pydantic\pydantic\pydantic
|
||||
|
||||
[isort]
|
||||
line_length=120
|
||||
known_first_party=pydantic
|
||||
multi_line_output=3
|
||||
include_trailing_comma=True
|
||||
force_grid_wrap=0
|
||||
combine_as_imports=True
|
||||
|
||||
[mypy]
|
||||
python_version = 3.9
|
||||
show_error_codes = True
|
||||
follow_imports = silent
|
||||
strict_optional = True
|
||||
warn_redundant_casts = True
|
||||
warn_unused_ignores = True
|
||||
disallow_any_generics = True
|
||||
check_untyped_defs = True
|
||||
no_implicit_reexport = True
|
||||
warn_unused_configs = True
|
||||
disallow_subclassing_any = True
|
||||
disallow_incomplete_defs = True
|
||||
disallow_untyped_decorators = True
|
||||
disallow_untyped_calls = True
|
||||
|
||||
# for strict mypy: (this is the tricky one :-))
|
||||
disallow_untyped_defs = True
|
||||
|
||||
# remaining arguments from `mypy --strict` which cause errors
|
||||
;no_implicit_optional = True
|
||||
;warn_return_any = True
|
||||
|
||||
[mypy-email_validator]
|
||||
ignore_missing_imports = true
|
||||
|
||||
[mypy-dotenv]
|
||||
ignore_missing_imports = true
|
||||
|
||||
[mypy-toml]
|
||||
ignore_missing_imports = true
|
||||
|
||||
# ansi2html and devtools are required to avoid the need to install these packages when running linting,
|
||||
# they're used in the docs build script
|
||||
[mypy-ansi2html]
|
||||
ignore_missing_imports = true
|
||||
|
||||
[mypy-devtools]
|
||||
ignore_missing_imports = true
|
||||
@@ -1,141 +1,26 @@
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from importlib.machinery import SourceFileLoader
|
||||
from pathlib import Path
|
||||
|
||||
from setuptools import setup
|
||||
|
||||
if os.name == 'nt':
|
||||
from setuptools.command import build_ext
|
||||
|
||||
def get_export_symbols(self, ext):
|
||||
"""
|
||||
Slightly modified from:
|
||||
https://github.com/python/cpython/blob/8849e5962ba481d5d414b3467a256aba2134b4da\
|
||||
/Lib/distutils/command/build_ext.py#L686-L703
|
||||
"""
|
||||
# Patch from: https://bugs.python.org/issue35893
|
||||
parts = ext.name.split('.')
|
||||
if parts[-1] == '__init__':
|
||||
suffix = parts[-2]
|
||||
else:
|
||||
suffix = parts[-1]
|
||||
|
||||
# from here on unchanged
|
||||
try:
|
||||
# Unicode module name support as defined in PEP-489
|
||||
# https://www.python.org/dev/peps/pep-0489/#export-hook-name
|
||||
suffix.encode('ascii')
|
||||
except UnicodeEncodeError:
|
||||
suffix = 'U' + suffix.encode('punycode').replace(b'-', b'_').decode('ascii')
|
||||
|
||||
initfunc_name = 'PyInit_' + suffix
|
||||
if initfunc_name not in ext.export_symbols:
|
||||
ext.export_symbols.append(initfunc_name)
|
||||
return ext.export_symbols
|
||||
|
||||
build_ext.build_ext.get_export_symbols = get_export_symbols
|
||||
sys.stderr.write(
|
||||
"""
|
||||
===============================
|
||||
Unsupported installation method
|
||||
===============================
|
||||
pydantic no longer supports installation with `python setup.py install`.
|
||||
Please use `python -m pip install .` instead.
|
||||
"""
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
class ReplaceLinks:
|
||||
def __init__(self):
|
||||
self.links = set()
|
||||
|
||||
def replace_issues(self, m):
|
||||
id = m.group(1)
|
||||
self.links.add(f'.. _#{id}: https://github.com/pydantic/pydantic/issues/{id}')
|
||||
return f'`#{id}`_'
|
||||
|
||||
def replace_users(self, m):
|
||||
name = m.group(2)
|
||||
self.links.add(f'.. _@{name}: https://github.com/{name}')
|
||||
return f'{m.group(1)}`@{name}`_'
|
||||
|
||||
def extra(self):
|
||||
return '\n\n' + '\n'.join(sorted(self.links)) + '\n'
|
||||
|
||||
|
||||
description = 'Data validation and settings management using python type hints'
|
||||
THIS_DIR = Path(__file__).resolve().parent
|
||||
try:
|
||||
history = (THIS_DIR / 'HISTORY.md').read_text(encoding='utf-8')
|
||||
history = re.sub(r'#(\d+)', r'[#\1](https://github.com/pydantic/pydantic/issues/\1)', history)
|
||||
history = re.sub(r'( +)@([\w\-]+)', r'\1[@\2](https://github.com/\2)', history, flags=re.I)
|
||||
history = re.sub('@@', '@', history)
|
||||
|
||||
long_description = (THIS_DIR / 'README.md').read_text(encoding='utf-8') + '\n\n' + history
|
||||
except FileNotFoundError:
|
||||
long_description = description + '.\n\nSee https://pydantic-docs.helpmanual.io/ for documentation.'
|
||||
|
||||
# avoid loading the package before requirements are installed:
|
||||
version = SourceFileLoader('version', 'pydantic/version.py').load_module()
|
||||
|
||||
ext_modules = None
|
||||
if not any(arg in sys.argv for arg in ['clean', 'check']) and 'SKIP_CYTHON' not in os.environ:
|
||||
try:
|
||||
from Cython.Build import cythonize
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
# For cython test coverage install with `make build-trace`
|
||||
compiler_directives = {}
|
||||
if 'CYTHON_TRACE' in sys.argv:
|
||||
compiler_directives['linetrace'] = True
|
||||
# Set CFLAG to all optimizations (-O3)
|
||||
# Any additional CFLAGS will be appended. Only the last optimization flag will have effect
|
||||
os.environ['CFLAGS'] = '-O3 ' + os.environ.get('CFLAGS', '')
|
||||
ext_modules = cythonize(
|
||||
'pydantic/*.py',
|
||||
exclude=['pydantic/generics.py'],
|
||||
nthreads=int(os.getenv('CYTHON_NTHREADS', 0)),
|
||||
language_level=3,
|
||||
compiler_directives=compiler_directives,
|
||||
)
|
||||
# The below code will never execute, however GitHub is particularly
|
||||
# picky about where it finds Python packaging metadata.
|
||||
# See: https://github.com/github/feedback/discussions/6456
|
||||
#
|
||||
# To be removed once GitHub catches up.
|
||||
|
||||
setup(
|
||||
name='pydantic',
|
||||
version=str(version.VERSION),
|
||||
description=description,
|
||||
long_description=long_description,
|
||||
long_description_content_type='text/markdown',
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3 :: Only',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Programming Language :: Python :: 3.9',
|
||||
'Programming Language :: Python :: 3.10',
|
||||
'Programming Language :: Python :: 3.11',
|
||||
'Intended Audience :: Developers',
|
||||
'Intended Audience :: Information Technology',
|
||||
'Intended Audience :: System Administrators',
|
||||
'License :: OSI Approved :: MIT License',
|
||||
'Operating System :: Unix',
|
||||
'Operating System :: POSIX :: Linux',
|
||||
'Environment :: Console',
|
||||
'Environment :: MacOS X',
|
||||
'Framework :: Hypothesis',
|
||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||
'Topic :: Internet',
|
||||
],
|
||||
author='Samuel Colvin',
|
||||
author_email='s@muelcolvin.com',
|
||||
url='https://github.com/pydantic/pydantic',
|
||||
license='MIT',
|
||||
packages=['pydantic'],
|
||||
package_data={'pydantic': ['py.typed']},
|
||||
python_requires='>=3.7',
|
||||
zip_safe=False, # https://mypy.readthedocs.io/en/latest/installed_packages.html
|
||||
install_requires=[
|
||||
'typing-extensions>=4.1.0'
|
||||
],
|
||||
extras_require={
|
||||
'email': ['email-validator>=1.0.3'],
|
||||
'dotenv': ['python-dotenv>=0.10.4'],
|
||||
},
|
||||
ext_modules=ext_modules,
|
||||
entry_points={'hypothesis': ['_ = pydantic._hypothesis_plugin']},
|
||||
)
|
||||
|
||||
@@ -9,14 +9,6 @@ from types import FunctionType
|
||||
import pytest
|
||||
from _pytest.assertion.rewrite import AssertionRewritingHook
|
||||
|
||||
# See https://hypothesis.readthedocs.io/en/latest/strategies.html#interaction-with-pytest-cov
|
||||
try:
|
||||
from hypothesis import given # noqa
|
||||
except ImportError:
|
||||
pytest_plugins = []
|
||||
else:
|
||||
pytest_plugins = ['hypothesis.extra.pytestplugin']
|
||||
|
||||
|
||||
def _extract_source_code_from_function(function):
|
||||
if function.__code__.co_argcount:
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
22: error: Unsupported operand types for + ("int" and "str") [operator]
|
||||
23: error: Unsupported operand types for + ("int" and "str") [operator]
|
||||
23: error: Unsupported operand types for + ("int" and "str") [operator]
|
||||
|
||||
@@ -1 +1 @@
|
||||
20: error: "Model" has no attribute "foobar" [attr-defined]
|
||||
20: error: "Model" has no attribute "foobar" [attr-defined]
|
||||
|
||||
@@ -1 +1 @@
|
||||
22: error: Argument 1 to "append" of "list" has incompatible type "str"; expected "int" [arg-type]
|
||||
22: error: Argument 1 to "append" of "list" has incompatible type "str"; expected "int" [arg-type]
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
14: error: Argument 2 to "foo" has incompatible type "int"; expected "str" [arg-type]
|
||||
15: error: Unexpected keyword argument "d" for "foo" [call-arg]
|
||||
17: error: "Callable[[int, DefaultNamedArg(str, 'c')], str]" has no attribute "raw_function" [attr-defined]
|
||||
26: error: Incompatible types in assignment (expression has type "str", variable has type "int") [assignment]
|
||||
26: error: Incompatible types in assignment (expression has type "str", variable has type "int") [assignment]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import importlib
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
@@ -16,10 +17,7 @@ except ImportError:
|
||||
parse_mypy_version = lambda _: (0,) # noqa: E731
|
||||
|
||||
|
||||
try:
|
||||
import dotenv
|
||||
except ImportError:
|
||||
dotenv = None
|
||||
pytestmark = pytest.mark.skipif(sys.platform != 'linux' and 'CI' in os.environ, reason='only run on linux when on CI')
|
||||
|
||||
# This ensures mypy can find the test files, no matter where tests are run from:
|
||||
os.chdir(Path(__file__).parent.parent.parent)
|
||||
@@ -54,7 +52,7 @@ cases = [
|
||||
executable_modules = list({fname[:-3] for _, fname, out_fname in cases if out_fname is None})
|
||||
|
||||
|
||||
@pytest.mark.skipif(not (dotenv and mypy_api), reason='dotenv or mypy are not installed')
|
||||
@pytest.mark.skipif(not mypy_api, reason='mypy is not installed')
|
||||
@pytest.mark.parametrize('config_filename,python_filename,output_filename', cases)
|
||||
def test_mypy_results(config_filename: str, python_filename: str, output_filename: str) -> None:
|
||||
full_config_filename = f'tests/mypy/configs/{config_filename}'
|
||||
@@ -96,7 +94,7 @@ def test_mypy_results(config_filename: str, python_filename: str, output_filenam
|
||||
assert actual_out == expected_out, actual_out
|
||||
|
||||
|
||||
@pytest.mark.skipif(not (dotenv and mypy_api), reason='dotenv or mypy are not installed')
|
||||
@pytest.mark.skipif(not mypy_api, reason='mypy is not installed')
|
||||
def test_bad_toml_config() -> None:
|
||||
full_config_filename = 'tests/mypy/configs/pyproject-plugin-bad-param.toml'
|
||||
full_filename = 'tests/mypy/modules/success.py'
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
black==22.8.0
|
||||
flake8==5.0.4
|
||||
flake8-quotes==3.3.1
|
||||
hypothesis==6.54.4
|
||||
isort==5.10.1
|
||||
pyupgrade==2.37.3
|
||||
mypy==0.971
|
||||
pre-commit==2.20.0
|
||||
pycodestyle==2.9.1
|
||||
pyflakes==2.5.0
|
||||
twine==4.0.1
|
||||
@@ -1,9 +0,0 @@
|
||||
coverage==6.4.4
|
||||
hypothesis==6.54.4
|
||||
# pin importlib-metadata as upper versions need typing-extensions to work if on Python < 3.8
|
||||
importlib-metadata==3.1.0;python_version<"3.8"
|
||||
mypy==0.971
|
||||
pytest==7.1.2
|
||||
pytest-cov==3.0.0
|
||||
pytest-mock==3.8.2
|
||||
pytest-sugar==0.9.5
|
||||
@@ -14,7 +14,6 @@ from pydantic import (
|
||||
NoneStrBytes,
|
||||
StrBytes,
|
||||
ValidationError,
|
||||
compiled,
|
||||
constr,
|
||||
errors,
|
||||
validate_model,
|
||||
@@ -22,11 +21,6 @@ from pydantic import (
|
||||
)
|
||||
from pydantic.fields import Field
|
||||
|
||||
try:
|
||||
import cython
|
||||
except ImportError:
|
||||
cython = None
|
||||
|
||||
|
||||
def test_str_bytes():
|
||||
class Model(BaseModel):
|
||||
@@ -244,9 +238,7 @@ def test_tuple_more():
|
||||
(dict, frozenset, list, set, tuple, type),
|
||||
],
|
||||
)
|
||||
@pytest.mark.skipif(
|
||||
sys.version_info < (3, 9) or compiled, reason='PEP585 generics only supported for python 3.9 and above'
|
||||
)
|
||||
@pytest.mark.skipif(sys.version_info < (3, 9), reason='PEP585 generics only supported for python 3.9 and above')
|
||||
def test_pep585_generic_types(dict_cls, frozenset_cls, list_cls, set_cls, tuple_cls, type_cls):
|
||||
class Type1:
|
||||
pass
|
||||
@@ -1874,29 +1866,6 @@ def test_default_factory_validator_child():
|
||||
assert Child(foo=['a', 'b']).foo == ['a-1', 'b-1']
|
||||
|
||||
|
||||
@pytest.mark.skipif(cython is None, reason='cython not installed')
|
||||
def test_cython_function_untouched():
|
||||
Model = cython.inline(
|
||||
# language=Python
|
||||
"""
|
||||
from pydantic import BaseModel
|
||||
|
||||
class Model(BaseModel):
|
||||
a = 0.0
|
||||
b = 10
|
||||
|
||||
def get_double_a(self) -> float:
|
||||
return self.a + self.b
|
||||
|
||||
return Model
|
||||
"""
|
||||
)
|
||||
model = Model(a=10.2)
|
||||
assert model.a == 10.2
|
||||
assert model.b == 10
|
||||
return model.get_double_a() == 20.2
|
||||
|
||||
|
||||
def test_resolve_annotations_module_missing(tmp_path):
|
||||
# see https://github.com/pydantic/pydantic/issues/2363
|
||||
file_path = tmp_path / 'module_to_load.py'
|
||||
|
||||
+1
-29
@@ -1,17 +1,14 @@
|
||||
import collections.abc
|
||||
import os
|
||||
import pickle
|
||||
import re
|
||||
import string
|
||||
import sys
|
||||
from copy import copy, deepcopy
|
||||
from typing import Callable, Dict, ForwardRef, List, NewType, Tuple, TypeVar, Union
|
||||
|
||||
import pytest
|
||||
from pkg_resources import safe_version
|
||||
from typing_extensions import Annotated, Literal
|
||||
|
||||
from pydantic import VERSION, BaseModel, ConstrainedList, conlist
|
||||
from pydantic import BaseModel, ConstrainedList, conlist
|
||||
from pydantic.color import Color
|
||||
from pydantic.dataclasses import dataclass
|
||||
from pydantic.fields import Undefined
|
||||
@@ -37,10 +34,8 @@ from pydantic.utils import (
|
||||
path_type,
|
||||
smart_deepcopy,
|
||||
to_lower_camel,
|
||||
truncate,
|
||||
unique_list,
|
||||
)
|
||||
from pydantic.version import version_info
|
||||
|
||||
try:
|
||||
import devtools
|
||||
@@ -95,19 +90,6 @@ def test_lenient_issubclass_is_lenient():
|
||||
assert lenient_issubclass('a', 'a') is False
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'input_value,output',
|
||||
[
|
||||
(object, "<class 'object'>"),
|
||||
(string.ascii_lowercase, "'abcdefghijklmnopq…'"),
|
||||
(list(range(20)), '[0, 1, 2, 3, 4, 5, …'),
|
||||
],
|
||||
)
|
||||
def test_truncate(input_value, output):
|
||||
with pytest.warns(DeprecationWarning, match='`truncate` is no-longer used by pydantic and is deprecated'):
|
||||
assert truncate(input_value, max_len=20) == output
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'input_value,output',
|
||||
[
|
||||
@@ -372,16 +354,6 @@ def test_get_model():
|
||||
get_model(C)
|
||||
|
||||
|
||||
def test_version_info():
|
||||
s = version_info()
|
||||
assert re.match(' *pydantic version: ', s)
|
||||
assert s.count('\n') == 5
|
||||
|
||||
|
||||
def test_standard_version():
|
||||
assert safe_version(VERSION) == VERSION
|
||||
|
||||
|
||||
def test_class_attribute():
|
||||
class Foo:
|
||||
attr = ClassAttribute('attr', 'foo')
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
import re
|
||||
|
||||
from packaging.version import parse as parse_version
|
||||
|
||||
import pydantic
|
||||
from pydantic.version import version_info
|
||||
|
||||
|
||||
def test_version_info():
|
||||
s = version_info()
|
||||
assert re.match(' *pydantic version: ', s)
|
||||
assert s.count('\n') == 4
|
||||
|
||||
|
||||
def test_standard_version():
|
||||
v = parse_version(pydantic.VERSION)
|
||||
assert str(v) == pydantic.VERSION
|
||||
|
||||
|
||||
def test_version_attribute_is_present():
|
||||
|
||||
Reference in New Issue
Block a user