Skip to content

Feature: integrate pycirclize into UltraPlot #2442

Feature: integrate pycirclize into UltraPlot

Feature: integrate pycirclize into UltraPlot #2442

Workflow file for this run

name: Matrix Test
on:
push:
branches: [main, devel]
pull_request:
branches: [main, devel]
jobs:
run-if-changes:
runs-on: ubuntu-latest
outputs:
run: ${{ (github.event_name == 'push' && github.ref_name == 'main') && 'true' || steps.filter.outputs.python }}
steps:
- uses: actions/checkout@v6
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
python:
- 'ultraplot/**'
select-tests:
runs-on: ubuntu-latest
needs:
- run-if-changes
if: always() && needs.run-if-changes.outputs.run == 'true'
outputs:
mode: ${{ steps.select.outputs.mode }}
tests: ${{ steps.select.outputs.tests }}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Prepare workspace
run: mkdir -p .ci
- name: Restore test map cache
id: restore-map
uses: actions/cache/restore@v4
with:
path: .ci/test-map.json
key: test-map-${{ github.event.pull_request.base.sha }}
restore-keys: |
test-map-
- name: Select impacted tests
id: select
run: |
if [ "${{ github.event_name }}" != "pull_request" ]; then
echo "mode=full" >> $GITHUB_OUTPUT
echo "tests=" >> $GITHUB_OUTPUT
exit 0
fi
git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.sha }} > .ci/changed.txt
python tools/ci/select_tests.py \
--map .ci/test-map.json \
--changed-files .ci/changed.txt \
--output .ci/selection.json \
--always-full 'pyproject.toml' \
--always-full 'environment.yml' \
--always-full 'ultraplot/__init__.py' \
--ignore 'docs/**' \
--ignore 'README.rst'
python - <<'PY' > .ci/selection.out
import json
data = json.load(open(".ci/selection.json", "r", encoding="utf-8"))
print(f"mode={data['mode']}")
print("tests=" + " ".join(data.get("tests", [])))
PY
cat .ci/selection.out >> $GITHUB_OUTPUT
get-versions:
runs-on: ubuntu-latest
needs:
- run-if-changes
if: always() && needs.run-if-changes.outputs.run == 'true'
outputs:
python-versions: ${{ steps.set-versions.outputs.python-versions }}
matplotlib-versions: ${{ steps.set-versions.outputs.matplotlib-versions }}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-python@v6
with:
python-version: "3.11"
- name: Install dependencies
run: pip install tomli
- id: set-versions
run: |
# Create a Python script to read and parse versions
cat > get_versions.py << 'EOF'
import tomli
import re
import json
# Read pyproject.toml
with open("pyproject.toml", "rb") as f:
data = tomli.load(f)
# Get Python version requirement
python_req = data["project"]["requires-python"]
# Parse min and max versions
min_version = re.search(r">=(\d+\.\d+)", python_req)
max_version = re.search(r"<(\d+\.\d+)", python_req)
python_versions = []
if min_version and max_version:
# Convert version strings to tuples
min_v = tuple(map(int, min_version.group(1).split(".")))
max_v = tuple(map(int, max_version.group(1).split(".")))
# Generate version list
current = min_v
while current < max_v:
python_versions.append(".".join(map(str, current)))
current = (current[0], current[1] + 1)
# parse MPL versions
mpl_req = None
for d in data["project"]["dependencies"]:
if d.startswith("matplotlib"):
mpl_req = d
break
assert mpl_req is not None, "matplotlib version not found in dependencies"
min_version = re.search(r">=(\d+\.\d+)", mpl_req)
max_version = re.search(r"<(\d+\.\d+)", mpl_req)
mpl_versions = []
if min_version and max_version:
# Convert version strings to tuples
min_v = tuple(map(int, min_version.group(1).split(".")))
max_v = tuple(map(int, max_version.group(1).split(".")))
# Generate version list
current = min_v
while current < max_v:
mpl_versions.append(".".join(map(str, current)))
current = (current[0], current[1] + 1)
# If no versions found, default to 3.9
if not mpl_versions:
mpl_versions = ["3.9"]
# Create output dictionary
output = {
"python_versions": python_versions,
"matplotlib_versions": mpl_versions
}
# Print as JSON
print(json.dumps(output))
EOF
# Run the script and capture output
OUTPUT=$(python3 get_versions.py)
PYTHON_VERSIONS=$(echo $OUTPUT | jq -r '.python_versions')
MPL_VERSIONS=$(echo $OUTPUT | jq -r '.matplotlib_versions')
echo "Detected Python versions: ${PYTHON_VERSIONS}"
echo "Detected Matplotlib versions: ${MPL_VERSIONS}"
echo "python-versions=$(echo $PYTHON_VERSIONS | jq -c)" >> $GITHUB_OUTPUT
echo "matplotlib-versions=$(echo $MPL_VERSIONS | jq -c)" >> $GITHUB_OUTPUT
build:
needs:
- get-versions
- run-if-changes
- select-tests
if: always() && needs.run-if-changes.outputs.run == 'true' && needs.get-versions.result == 'success' && needs.select-tests.result == 'success'
strategy:
matrix:
python-version: ${{ fromJson(needs.get-versions.outputs.python-versions) }}
matplotlib-version: ${{ fromJson(needs.get-versions.outputs.matplotlib-versions) }}
fail-fast: false
uses: ./.github/workflows/build-ultraplot.yml
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.python-version }}-${{ matrix.matplotlib-version }}
cancel-in-progress: true
with:
python-version: ${{ matrix.python-version }}
matplotlib-version: ${{ matrix.matplotlib-version }}
test-mode: ${{ needs.select-tests.outputs.mode }}
test-nodeids: ${{ needs.select-tests.outputs.tests }}
unit-tests:
name: Unit Tests (coverage focus)
needs:
- run-if-changes
if: always() && needs.run-if-changes.outputs.run == 'true'
runs-on: ubuntu-latest
defaults:
run:
shell: bash -el {0}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: mamba-org/setup-micromamba@v2.0.7
with:
environment-file: ./environment.yml
init-shell: bash
create-args: >-
--verbose
python=3.11
matplotlib=3.9
cache-environment: true
cache-downloads: false
- name: Build Ultraplot
run: |
pip install --no-build-isolation --no-deps .
- name: Run unit tests
run: |
pytest -n auto --cov=ultraplot --cov-branch --cov-report term-missing --cov-report=xml -m "not mpl_image_compare" ultraplot/tests
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
slug: Ultraplot/ultraplot
build-success:
needs:
- build
- unit-tests
- run-if-changes
if: always()
runs-on: ubuntu-latest
steps:
- run: |
if [[ '${{ needs.run-if-changes.outputs.run }}' == 'false' ]]; then
echo "No changes detected, tests skipped."
else
if [[ '${{ needs.build.result }}' == 'success' && '${{ needs.unit-tests.result }}' == 'success' ]]; then
echo "All tests passed successfully!"
else
echo "Tests failed!"
exit 1
fi
fi