Skip to content

Recursively unpack Literal values if using PEP 695 type aliases (#1… #28

Recursively unpack Literal values if using PEP 695 type aliases (#1…

Recursively unpack Literal values if using PEP 695 type aliases (#1… #28

Workflow file for this run

name: CI
on:
push:
branches:
- main
tags:
- '**'
pull_request: {}
env:
COLUMNS: 150
UV_FROZEN: true
jobs:
lint:
runs-on: ubuntu-latest
name: Lint ${{ matrix.python-version }}
strategy:
fail-fast: false
matrix:
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v4
with:
enable-cache: true
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: uv sync --group linting --all-extras
- uses: pre-commit/[email protected]
with:
extra_args: --all-files --verbose
env:
SKIP: no-commit-to-branch
docs-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v4
with:
enable-cache: true
python-version: '3.12'
- name: Install dependencies
# Unlike the docs build, we don't use mkdocs_material-insiders
# Because the secret for accessing the library is not accessible from forks, but we still want to run
# this job on public CI runs.
run: uv sync --group docs
- run: uv run python -c 'import docs.plugins.main'
# Adding local symlinks gets nice source locations like
# pydantic_core/core_schema.py
# instead of
# .venv/lib/python3.10/site-packages/pydantic_core/core_schema.py
- name: prepare shortcuts for extra modules
run: |
ln -s .venv/lib/python*/site-packages/pydantic_core pydantic_core
ln -s .venv/lib/python*/site-packages/pydantic_settings pydantic_settings
ln -s .venv/lib/python*/site-packages/pydantic_extra_types pydantic_extra_types
- run: uv run mkdocs build
test-memray:
name: Test memray
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v4
with:
enable-cache: true
python-version: '3.12'
- name: install deps
run: uv sync --group testing-extra
- name: Run tests
run: uv run pytest --ignore=tests/mypy/ --ignore=tests/test_docs.py --memray
test:
name: Test ${{ matrix.os }} / ${{ matrix.python-version }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-13, macos-latest, windows-latest]
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
include:
# no pydantic-core binaries for pypy on windows, so tests take absolute ages
# macos tests with pypy take ages (>10mins) since pypy is very slow
# so we only test pypy on ubuntu
- os: ubuntu-latest
python-version: 'pypy3.9'
- os: ubuntu-latest
python-version: 'pypy3.10'
exclude:
# Python 3.8 and 3.9 are not available on macOS 14
- os: macos-13
python-version: '3.10'
- os: macos-13
python-version: '3.11'
- os: macos-13
python-version: '3.12'
- os: macos-latest
python-version: '3.13'
- os: macos-latest
python-version: '3.8'
- os: macos-latest
python-version: '3.9'
env:
OS: ${{ matrix.os }}
DEPS: yes
UV_PYTHON_PREFERENCE: only-managed
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v4
with:
enable-cache: true
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: uv sync --extra timezone
- run: 'uv run python -c "import pydantic.version; print(pydantic.version.version_info())"'
- run: mkdir coverage
- name: Test without email-validator
# speed up by skipping this step on pypy
if: "!startsWith(matrix.python-version, 'pypy')"
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 dependencies
run: uv sync --group testing-extra --all-extras
- name: Test with all extra dependencies
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@v4
with:
name: coverage-${{ matrix.os }}-${{ matrix.python-version }}
path: coverage
include-hidden-files: true
test-fastapi:
# If some tests start failing due to out-of-date schemas/validation errors/etc.,
# update the `tests/test_fastapi.sh` script to exclude tests that have known-acceptable failures.
name: Test FastAPI
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: set up python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Run tests
run: make test-fastapi
test-plugin:
name: Test Pydantic plugin
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v4
with:
python-version: '3.12'
- name: Install dependencies
run: uv sync
- name: Install example plugin
run: uv pip install ./tests/plugin
- run: uv run pytest tests/plugin
env:
TEST_PLUGIN: 1
test-mypy:
name: mypy ${{ matrix.mypy-version }} / ${{ matrix.python-version }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# test the latest version on all supported Python versions and the rest on 3.12
mypy-version: ['1.10.1', '1.11.2']
python-version: ['3.12']
include:
- mypy-version: '1.12.0'
python-version: '3.8'
- mypy-version: '1.12.0'
python-version: '3.9'
- mypy-version: '1.12.0'
python-version: '3.10'
- mypy-version: '1.12.0'
python-version: '3.11'
- mypy-version: '1.12.0'
python-version: '3.12'
- mypy-version: '1.12.0'
python-version: '3.13'
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v4
with:
enable-cache: true
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: uv sync --group typechecking --all-extras
- name: Install mypy
if: steps.cache.outputs.cache-hit != 'true'
run: uv pip install 'mypy==${{ matrix.mypy-version }}'
- run: mkdir coverage
- name: Run mypy tests
run: uv run coverage run -m pytest tests/mypy --test-mypy
env:
COVERAGE_FILE: coverage/.coverage.linux-py${{ matrix.python-version }}-mypy${{ matrix.mypy-version }}
CONTEXT: linux-py${{ matrix.python-version }}-mypy${{ matrix.mypy-version }}
- name: Store coverage files
uses: actions/upload-artifact@v4
with:
name: coverage-${{ matrix.python-version }}-mypy${{ matrix.mypy-version }}
path: coverage
include-hidden-files: true
test-typechecking-integration:
name: Typechecking integration tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v3
with:
enable-cache: true
python-version: '3.12'
- name: Install dependencies
run: uv sync --group typechecking
- name: Run typechecking integration tests (Pyright)
run: make test-typechecking-pyright
- name: Run typechecking integration tests (Mypy)
run: make test-typechecking-mypy
coverage-combine:
needs: [test, test-mypy]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Get coverage files
uses: actions/download-artifact@v4
with:
merge-multiple: true
pattern: coverage-*
path: coverage
- run: pip install coverage[toml]
- run: ls -la coverage
- run: coverage combine coverage
- run: coverage report
- run: coverage html --show-contexts --title "pydantic coverage for ${{ github.sha }}"
- name: Store coverage data
uses: actions/upload-artifact@v4
with:
name: coverage-data
path: .coverage
include-hidden-files: true
- name: Store coverage HTML
uses: actions/upload-artifact@v4
with:
name: coverage-html
path: htmlcov
coverage-pr-comment:
needs: coverage-combine
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
permissions:
pull-requests: write
contents: write
steps:
- uses: actions/checkout@v4
- name: Download coverage data
uses: actions/download-artifact@v4
with:
name: coverage-data
- name: Generate coverage comment
id: coverage-comment
uses: py-cov-action/python-coverage-comment-action@v3
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Store coverage comment
uses: actions/upload-artifact@v4
if: steps.coverage-comment.outputs.COMMENT_FILE_WRITTEN == 'true'
with:
name: python-coverage-comment-action
path: python-coverage-comment-action.txt
test-typing-extensions:
name: Test typing-extensions (`main` branch) on Python ${{ matrix.python-version }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v4
with:
enable-cache: true
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: uv sync
- name: Install typing-extensions
run: uv pip install 'typing-extensions @ git+https://github.com/python/typing_extensions.git'
- name: Run tests
run: make test
# https://github.com/marketplace/actions/alls-green
check: # This job does nothing and is only used for the branch protection
if: always()
outputs:
result: ${{ steps.all-green.outputs.result }}
needs:
- lint
- docs-build
- test
- test-memray
- test-mypy
- test-fastapi
- test-plugin
runs-on: ubuntu-latest
steps:
- name: Decide whether the needed jobs succeeded or failed
uses: re-actors/alls-green@release/v1
id: all-green
with:
jobs: ${{ toJSON(needs) }}
release:
needs: [check]
if: needs.check.outputs.result == 'success' && startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
environment: release
permissions:
id-token: write
outputs:
pydantic-version: ${{ steps.check-tag.outputs.VERSION }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install 'build' library
run: pip install -U build
- name: Check version
id: check-tag
uses: samuelcolvin/[email protected]
with:
version_file_path: pydantic/version.py
- name: Build library
run: python -m build
- name: Upload package to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
send-tweet:
name: Send tweet
needs: [release]
if: needs.release.result == 'success'
runs-on: ubuntu-latest
steps:
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
run: pip install tweepy==4.14.0
- name: Send tweet
shell: python
run: |
import os
import tweepy
client = tweepy.Client(
access_token=os.getenv("TWITTER_ACCESS_TOKEN"),
access_token_secret=os.getenv("TWITTER_ACCESS_TOKEN_SECRET"),
consumer_key=os.getenv("TWITTER_CONSUMER_KEY"),
consumer_secret=os.getenv("TWITTER_CONSUMER_SECRET"),
)
version = os.getenv("VERSION").strip('"')
if "b" in version:
official_version = version[:version.index("b")]
tweet = os.getenv("BETA_TWEET").format(version=version, official_version=official_version)
else:
tweet = os.getenv("TWEET").format(version=version)
client.create_tweet(text=tweet)
env:
VERSION: ${{ needs.release.outputs.pydantic-version }}
TWEET: |
Pydantic version {version} is out! 🎉
https://github.com/pydantic/pydantic/releases/tag/v{version}
BETA_TWEET: |
Pydantic beta version {version} is out! 🚀
Please try v{version} in the next week before we release v{official_version},
and let us know if you encounter any issues!
https://github.com/pydantic/pydantic/releases/tag/v{version}
TWITTER_CONSUMER_KEY: ${{ secrets.TWITTER_CONSUMER_KEY }}
TWITTER_CONSUMER_SECRET: ${{ secrets.TWITTER_CONSUMER_SECRET }}
TWITTER_ACCESS_TOKEN: ${{ secrets.TWITTER_ACCESS_TOKEN }}
TWITTER_ACCESS_TOKEN_SECRET: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }}