Skip to content

fix(dspy): render PEP 604 unions like typing.Union in get_annotation_… #138

fix(dspy): render PEP 604 unions like typing.Union in get_annotation_…

fix(dspy): render PEP 604 unions like typing.Union in get_annotation_… #138

---
name: Publish Python 🐍 distributions 📦 to PyPI
on:
push:
tags:
- "*"
permissions: {}
jobs:
extract-tag:
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
version: ${{ steps.extract_tag.outputs.tag }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- id: extract_tag
name: Extract tag name
run: echo "tag=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT"
build-and-publish-test-pypi:
needs: extract-tag
runs-on: ubuntu-latest
environment:
name: testpypi
permissions:
contents: read
id-token: write # IMPORTANT: mandatory for trusted publishing
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Set up Python 3.11
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.11"
- name: Install dependencies
run: python3 -m pip install --upgrade setuptools wheel twine build semver packaging
- name: Install Deno
uses: denoland/setup-deno@22d081ff2d3a40755e97629de92e3bcbfa7cf2ed # v2.0.5
with:
deno-version: v2.7.7
- name: Get correct version for TestPyPI release
id: check_version
env:
VERSION: ${{ needs.extract-tag.outputs.version }}
run: |
PACKAGE_NAME="dspy-ai-test-isaac"
echo "Checking if $VERSION for $PACKAGE_NAME exists on TestPyPI"
NEW_VERSION=$(python3 .github/workflows/build_utils/test_version.py "$PACKAGE_NAME" "$VERSION")
echo "Version to be used for TestPyPI release: $NEW_VERSION"
echo "version=$NEW_VERSION" >> "$GITHUB_OUTPUT"
- name: Update version in pyproject.toml
env:
VERSION: ${{ steps.check_version.outputs.version }}
run: sed -i "/#replace_package_version_marker/{n;s/version=\"[^\"]*\"/version=\"$VERSION\"/;}" pyproject.toml
- name: Update package name in pyproject.toml
run: sed -i '/#replace_package_name_marker/{n;s/name="[^"]*"/name="dspy-ai-test-isaac"/;}' pyproject.toml
- name: Build a binary wheel
run: python3 -m build
- name: Validate built distributions
run: python3 -m twine check --strict dist/*
# Test the locally built wheel
- name: Create test environment
run: python -m venv test_before_testpypi
- name: Test package installation and functionality
run: |
source test_before_testpypi/bin/activate
# Install the locally built wheel and testing dependencies
pip install dist/*.whl pytest pytest-asyncio pytest-mock
pytest tests/metadata/test_metadata.py tests/predict
(cd "$RUNNER_TEMP" && python -c 'import dspy; assert dspy.PythonInterpreter().execute("6 * 7") == 42')
deactivate
# Publish to test-PyPI
- name: Publish distribution 📦 to test-PyPI
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1 # This requires a trusted publisher to be setup in pypi/testpypi
with:
repository-url: https://test.pypi.org/legacy/
# TODO: Add tests using dspy-ai-test
build-and-publish-pypi:
needs: [extract-tag, build-and-publish-test-pypi]
# Only publish to PyPI if the repository owner is stanfordnlp
if: github.repository_owner == 'stanfordnlp'
runs-on: ubuntu-latest
environment:
name: pypi
permissions:
contents: read
id-token: write # IMPORTANT: mandatory for trusted publishing
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Set up Python 3.11
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.11"
- name: Install dependencies
run: python3 -m pip install --upgrade setuptools wheel twine build
- name: Install Deno
uses: denoland/setup-deno@22d081ff2d3a40755e97629de92e3bcbfa7cf2ed # v2.0.5
with:
deno-version: v2.7.7
- name: Update version in pyproject.toml
env:
VERSION: ${{ needs.extract-tag.outputs.version }}
run: sed -i "/#replace_package_version_marker/{n;s/version *= *\"[^\"]*\"/version=\"$VERSION\"/;}" pyproject.toml
- name: Update version in __metadata__.py
env:
VERSION: ${{ needs.extract-tag.outputs.version }}
run: sed -i "/#replace_package_version_marker/{n;s/__version__ *= *\"[^\"]*\"/__version__=\"$VERSION\"/;}" ./dspy/__metadata__.py
# Publish to dspy
- name: Update package name in pyproject.toml
run: sed -i '/#replace_package_name_marker/{n;s/name *= *"[^"]*"/name="dspy"/;}' pyproject.toml
- name: Update package name in metadata.py
run: sed -i '/#replace_package_name_marker/{n;s/__name__ *= *"[^"]*"/__name__="dspy"/;}' ./dspy/__metadata__.py
- name: Build a binary wheel
run: python3 -m build
- name: Validate built distributions
run: python3 -m twine check --strict dist/*
# Test the locally built wheel before publishing to pypi
- name: Create test environment
run: python -m venv test_before_pypi
- name: Test package installation and functionality
run: |
source test_before_pypi/bin/activate
# Install the locally built wheel and testing dependencies
pip install dist/*.whl pytest pytest-asyncio pytest-mock
pytest tests/metadata/test_metadata.py tests/predict
(cd "$RUNNER_TEMP" && python -c 'import dspy; assert dspy.PythonInterpreter().execute("6 * 7") == 42')
deactivate
rm -r test_before_pypi
- name: Preserve the exact release wheel for documentation
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: dspy-release-wheel
path: dist/*.whl
if-no-files-found: error
- name: Publish distribution 📦 to PyPI (dspy)
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
with:
attestations: false
# Publish to dspy-ai
- name: Update package name in pyproject.toml
run: sed -i '/#replace_package_name_marker/{n;s/name *= *"[^"]*"/name="dspy-ai"/;}' .github/.internal_dspyai/pyproject.toml
- name: Update version for dspy-ai release
env:
VERSION: ${{ needs.extract-tag.outputs.version }}
run: sed -i "/#replace_package_version_marker/{n;s/version *= *\"[^\"]*\"/version=\"$VERSION\"/;}" .github/.internal_dspyai/pyproject.toml
- name: Update dspy dependency for dspy-ai release
env:
VERSION: ${{ needs.extract-tag.outputs.version }}
run: sed -i "/#replace_dspy_version_marker/{n;s/dspy>=[^\"]*/dspy>=$VERSION/;}" .github/.internal_dspyai/pyproject.toml
- name: Build a binary wheel (dspy-ai)
run: python3 -m build .github/.internal_dspyai/
- name: Validate built distributions (dspy-ai)
run: python3 -m twine check --strict .github/.internal_dspyai/dist/*
- name: Publish distribution 📦 to PyPI (dspy-ai)
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
with:
attestations: false
packages-dir: .github/.internal_dspyai/dist/
release-docs:
needs: [extract-tag, build-and-publish-pypi]
if: github.repository_owner == 'stanfordnlp'
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
fetch-depth: 0
- name: Check whether this is a documentation release
id: publishable
env:
VERSION: ${{ needs.extract-tag.outputs.version }}
run: |
if [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+((a|b|rc)[0-9]+)?$ ]] && (( ${VERSION%%.*} >= 3 )); then
echo "publish=true" >> "$GITHUB_OUTPUT"
else
echo "publish=false" >> "$GITHUB_OUTPUT"
fi
- name: Set up Python 3.11
if: steps.publishable.outputs.publish == 'true'
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.11"
- name: Download exact production wheel
if: steps.publishable.outputs.publish == 'true'
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
name: dspy-release-wheel
path: release-wheel
- name: Install documentation dependencies and release wheel
if: steps.publishable.outputs.publish == 'true'
run: python -m pip install -r docs/requirements.txt release-wheel/*.whl
- name: Verify API introspection uses the release wheel
if: steps.publishable.outputs.publish == 'true'
run: |
cd "$RUNNER_TEMP"
env -u PYTHONPATH PYTHONSAFEPATH=1 python -P - <<'PY'
import site
from pathlib import Path
import dspy
module = Path(dspy.__file__).resolve()
site_packages = [Path(root).resolve() for root in site.getsitepackages()]
if not any(module.is_relative_to(root) for root in site_packages):
raise SystemExit(f"DSPy resolved outside site-packages: {module}")
print(f"DSPy API source: {module}")
PY
- name: Build immutable release documentation
if: steps.publishable.outputs.publish == 'true'
env:
VERSION: ${{ needs.extract-tag.outputs.version }}
run: |
cd "$RUNNER_TEMP"
env PYTHONPATH="$GITHUB_WORKSPACE/docs/scripts" PYTHONSAFEPATH=1 python -P \
"$GITHUB_WORKSPACE/docs/scripts/build_docs.py" release \
--config "$GITHUB_WORKSPACE/docs/mkdocs.yml" \
--output "$GITHUB_WORKSPACE/release-site" \
--version "$VERSION" \
--artifact "$GITHUB_WORKSPACE"/release-wheel/*.whl \
--package-source workflow-wheel
- name: Check out documentation deployment
if: steps.publishable.outputs.publish == 'true'
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
repository: krypticmouse/dspy-docs
ref: master
path: docs-deployment
persist-credentials: false
token: ${{ secrets.GH_PAT }} # zizmor: ignore[secrets-outside-env]
- name: Publish immutable release documentation
if: steps.publishable.outputs.publish == 'true'
env:
GH_TOKEN: ${{ secrets.GH_PAT }}
VERSION: ${{ needs.extract-tag.outputs.version }}
run: |
gh auth setup-git
git -C docs-deployment config user.name github-actions
git -C docs-deployment config user.email github-actions@github.com
aliases=()
if [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
aliases=(--alias "${VERSION%.*}")
fi
for attempt in 1 2 3; do
git -C docs-deployment fetch origin master
git -C docs-deployment reset --hard origin/master
python docs/scripts/publish_versioned_docs.py \
--repository docs-deployment \
--site release-site \
--identifier "$VERSION" \
"${aliases[@]}" \
--package-source workflow-wheel \
--branch master \
--require-current-renderer zensical
if git -C docs-deployment push origin master; then
exit 0
fi
sleep $((2 ** attempt + RANDOM % 5))
done
echo "::error::Documentation deployment changed repeatedly; rerun this release job"
exit 1
open-main-version-bump-pr:
needs: [extract-tag, build-and-publish-pypi]
if: github.repository_owner == 'stanfordnlp'
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
ref: main
- name: Apply version bump for main
env:
VERSION: ${{ needs.extract-tag.outputs.version }}
run: |
sed -i "/#replace_package_version_marker/{n;s/version *= *\"[^\"]*\"/version=\"$VERSION\"/;}" pyproject.toml
sed -i "/#replace_package_version_marker/{n;s/__version__ *= *\"[^\"]*\"/__version__=\"$VERSION\"/;}" ./dspy/__metadata__.py
sed -i "/#replace_package_version_marker/{n;s/version *= *\"[^\"]*\"/version=\"$VERSION\"/;}" .github/.internal_dspyai/pyproject.toml
sed -i "/#replace_dspy_version_marker/{n;s/dspy>=[^\"]*/dspy>=$VERSION/;}" .github/.internal_dspyai/pyproject.toml
- name: Open version bump PR for main
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
with:
branch: release-${{ needs.extract-tag.outputs.version }}-main-version-bump
base: main
add-paths: |
pyproject.toml
dspy/__metadata__.py
.github/.internal_dspyai/pyproject.toml
commit-message: Update versions for ${{ needs.extract-tag.outputs.version }}
title: Update versions for ${{ needs.extract-tag.outputs.version }}
body: |
Updates main version metadata after publishing ${{ needs.extract-tag.outputs.version }}.