Skip to content

Commit

Permalink
maintain stable versions of dependencies (PennyLaneAI#5158)
Browse files Browse the repository at this point in the history
**Context:**
There are many difficulties with dependency management, and this PR
tries to address two of them:
- reproducible versions of PL+deps from a past version
- ability to view which deps have been auto-updated (eg. a new version
of an unbound dep is released) and when

**Description of the Change:**
- Factor out the python environment setup to its own file. All default
package versions are here now
- Update `interface-unit-tests` to trigger the upload of `pip freeze`
results as artifacts for later use. happens in the `core`, `jax`, `tf`,
`torch`, `all-interfaces` and `external` test suites today (ensured that
it only occurs on one worker using `strategy.job-index`)
- Add the `upload-stable-deps` workflow to run after tests complete. The
action only runs on merge commits to master, so users shouldn't see it.
This is the real new feature, and here's how it works:
1. create the branch `bot/stable-deps-update` (or rebases it on master
if it already existed)
2. delete the existing requirement files in `.github/stable/` to avoid
merge conflicts
3. download the previously-uploaded requirement files generated in this
flow to that same folder and check if there's a diff
  4. if no diff, do nothing!
5. if there's a diff and no PR exists, it opens one and tags me (and
hopefully the team because of CODEOWNERS)
6. if there's a diff and a PR already exists, it just pushes to the
existing PR branch (confirmed this is the case despite the open-pr step
running - it just does nothing in that case)

**Benefits:**
Helps with both difficulties mentioned in the context section above

**Possible Drawbacks:**
- the team will have to review this PR (if it becomes too noisy, we can
turn this into a cronjob)
- commits made by bots (eg. actions that use `${{ secrets.GITHUB_TOKEN
}}`) will not trigger CI, so the automated PRs need to have it triggered
manually. A hack to fix this is proposed
[here](peter-evans/create-pull-request#48 (comment))
if we want to consider that, but this is a feature of GitHub (not a
bug), intended to avoid infinite CI loops

I will do something similar for the docs builds after this PR is merged,
it's complex enough for now.

[sc-56376]
  • Loading branch information
timmysilv authored and Gabriel-Bottrill committed Feb 14, 2024
1 parent 5f20ca3 commit 5f750f0
Show file tree
Hide file tree
Showing 5 changed files with 202 additions and 78 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
@@ -0,0 +1 @@
/.github/stable/ @PennyLaneAI/Core
113 changes: 113 additions & 0 deletions .github/workflows/install_deps/action.yml
@@ -0,0 +1,113 @@
name: Install Dependencies
description: |
This workflow installs Python, PennyLane and all its dependencies. If a
requirements file is provided, it will upload the results of pip freeze
as well.
inputs:
python_version:
description: The version of Python to use in order to run unit tests
required: false
default: '3.9'
install_jax:
description: Indicate if JAX should be installed or not
required: false
default: 'true'
jax_version:
description: The version of JAX to install for any job that requires JAX
required: false
default: 0.4.23
install_tensorflow:
description: Indicate if TensorFlow should be installed or not
required: false
default: 'true'
tensorflow_version:
description: The version of TensorFlow to install for any job that requires TensorFlow
required: false
default: 2.15.0
install_pytorch:
description: Indicate if PyTorch should be installed or not
required: false
default: 'true'
pytorch_version:
description: The version of PyTorch to install for any job that requires PyTorch
required: false
default: 2.2.0
install_pennylane_lightning_master:
description: Indicate if PennyLane-Lightning should be installed from the master branch
required: false
default: 'true'
additional_pip_packages:
description: Additional packages to install. Values will be passed to pip install {value}
required: false
default: ''
requirements_file:
description: File name to store stable version of requirements for a test group
required: false
default: ''

runs:
using: composite
steps:
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '${{ inputs.python_version }}'

- name: Upgrade PIP
shell: bash
run: pip install --upgrade pip && pip install wheel --upgrade

- name: Install PennyLane dependencies
shell: bash
run: |
pip install -r requirements-ci.txt --upgrade
pip install -r requirements-dev.txt --upgrade
- name: Install PyTorch
shell: bash
if: inputs.install_pytorch == 'true'
env:
TORCH_VERSION: ${{ inputs.pytorch_version != '' && format('=={0}', inputs.pytorch_version) || '' }}
run: pip install "torch${{ env.TORCH_VERSION }}" -f https://download.pytorch.org/whl/torch_stable.html

- name: Install TensorFlow
shell: bash
if: inputs.install_tensorflow == 'true'
env:
TF_VERSION: ${{ inputs.tensorflow_version != '' && format('~={0}', inputs.tensorflow_version) || '' }}
run: pip install "tensorflow${{ env.TF_VERSION }}" "keras${{ env.TF_VERSION }}"

- name: Install JAX
shell: bash
if: inputs.install_jax == 'true'
env:
JAX_VERSION: ${{ inputs.jax_version != '' && format('=={0}', inputs.jax_version) || '' }}
run: pip install "jax${{ env.JAX_VERSION}}" "jaxlib${{ env.JAX_VERSION }}"

- name: Install additional PIP packages
shell: bash
if: inputs.additional_pip_packages != ''
run: pip install ${{ inputs.additional_pip_packages }}

- name: Install PennyLane
shell: bash
run: |
python setup.py bdist_wheel
pip install dist/PennyLane*.whl
- name: Install PennyLane-Lightning master
shell: bash
if: inputs.install_pennylane_lightning_master == 'true'
run: pip install -i https://test.pypi.org/simple/ PennyLane-Lightning --pre --upgrade

- name: Freeze dependencies
shell: bash
if: inputs.requirements_file != ''
run: pip freeze | grep -v "file:///" > ${{ inputs.requirements_file }}

- name: Upload frozen requirements
if: inputs.requirements_file != ''
uses: actions/upload-artifact@v4
with:
name: frozen-${{ inputs.requirements_file }}
path: ${{ inputs.requirements_file }}
40 changes: 7 additions & 33 deletions .github/workflows/interface-unit-tests.yml
Expand Up @@ -11,21 +11,6 @@ on:
required: false
type: string
default: 'unit-tests'
jax_version:
description: The version of JAX to install for any job that requires JAX
required: false
type: string
default: 0.4.23
tensorflow_version:
description: The version of TensorFlow to install for any job that requires TensorFlow
required: false
type: string
default: 2.15.0
pytorch_version:
description: The version of PyTorch to install for any job that requires PyTorch
required: false
type: string
default: 2.2.0
pytest_coverage_flags:
description: PyTest Coverage flags to pass to all jobs
required: false
Expand Down Expand Up @@ -162,10 +147,10 @@ jobs:
install_jax: false
install_tensorflow: false
install_pytorch: true
pytorch_version: ${{ inputs.pytorch_version }}
install_pennylane_lightning_master: true
pytest_coverage_flags: ${{ inputs.pytest_coverage_flags }}
pytest_markers: torch and not qcut and not finite-diff and not param-shift
requirements_file: ${{ strategy.job-index == 0 && 'torch.txt' || '' }}


autograd-tests:
Expand Down Expand Up @@ -225,13 +210,13 @@ jobs:
pipeline_mode: ${{ inputs.pipeline_mode }}
install_jax: false
install_tensorflow: true
tensorflow_version: ${{ inputs.tensorflow_version }}
install_pytorch: false
install_pennylane_lightning_master: true
pytest_coverage_flags: ${{ inputs.pytest_coverage_flags }}
pytest_markers: tf and not qcut and not finite-diff and not param-shift
pytest_additional_args: --splits 3 --group ${{ matrix.group }} --durations-path='.github/workflows/tf_tests_durations.json'
additional_pip_packages: pytest-split
requirements_file: ${{ strategy.job-index == 0 && 'tf.txt' || '' }}


jax-tests:
Expand Down Expand Up @@ -259,14 +244,14 @@ jobs:
python_version: ${{ matrix.python-version }}
pipeline_mode: ${{ inputs.pipeline_mode }}
install_jax: true
jax_version: ${{ inputs.jax_version }}
install_tensorflow: false
install_pytorch: false
install_pennylane_lightning_master: true
pytest_coverage_flags: ${{ inputs.pytest_coverage_flags }}
pytest_markers: jax and not qcut and not finite-diff and not param-shift
pytest_additional_args: --splits 5 --group ${{ matrix.group }} --durations-path='.github/workflows/jax_tests_durations.json'
additional_pip_packages: pytest-split
requirements_file: ${{ strategy.job-index == 0 && 'jax.txt' || '' }}


core-tests:
Expand Down Expand Up @@ -303,6 +288,7 @@ jobs:
pytest_markers: core and not qcut and not finite-diff and not param-shift
pytest_additional_args: --splits 2 --group ${{ matrix.group }}
additional_pip_packages: pytest-split
requirements_file: ${{ strategy.job-index == 0 && 'core.txt' || '' }}


all-interfaces-tests:
Expand All @@ -329,14 +315,12 @@ jobs:
python_version: ${{ matrix.python-version }}
pipeline_mode: ${{ inputs.pipeline_mode }}
install_jax: true
jax_version: ${{ inputs.jax_version }}
install_tensorflow: true
tensorflow_version: ${{ inputs.tensorflow_version }}
install_pytorch: true
pytorch_version: ${{ inputs.pytorch_version }}
install_pennylane_lightning_master: false
pytest_coverage_flags: ${{ inputs.pytest_coverage_flags }}
pytest_markers: all_interfaces
requirements_file: ${{ strategy.job-index == 0 && 'all_interfaces.txt' || '' }}


external-libraries-tests:
Expand All @@ -363,14 +347,13 @@ jobs:
python_version: ${{ matrix.python-version }}
pipeline_mode: ${{ inputs.pipeline_mode }}
install_jax: true
jax_version: ${{ inputs.jax_version }}
install_tensorflow: true
tensorflow_version: ${{ inputs.tensorflow_version }}
install_pytorch: false
install_pennylane_lightning_master: false
pytest_coverage_flags: ${{ inputs.pytest_coverage_flags }}
pytest_markers: external
additional_pip_packages: git+https://github.com/Quantomatic/pyzx.git@master pennylane-catalyst matplotlib stim
additional_pip_packages: pyzx pennylane-catalyst matplotlib stim
requirements_file: ${{ strategy.job-index == 0 && 'external.txt' || '' }}


qcut-tests:
Expand All @@ -397,11 +380,8 @@ jobs:
python_version: ${{ matrix.python-version }}
pipeline_mode: ${{ inputs.pipeline_mode }}
install_jax: true
jax_version: ${{ inputs.jax_version }}
install_tensorflow: true
tensorflow_version: ${{ inputs.tensorflow_version }}
install_pytorch: true
pytorch_version: ${{ inputs.pytorch_version }}
install_pennylane_lightning_master: false
pytest_coverage_flags: ${{ inputs.pytest_coverage_flags }}
pytest_markers: qcut
Expand Down Expand Up @@ -466,11 +446,8 @@ jobs:
python_version: ${{ matrix.python-version }}
pipeline_mode: ${{ inputs.pipeline_mode }}
install_jax: true
jax_version: ${{ inputs.jax_version }}
install_tensorflow: true
tensorflow_version: ${{ inputs.tensorflow_version }}
install_pytorch: true
pytorch_version: ${{ inputs.pytorch_version }}
install_pennylane_lightning_master: false
pytest_coverage_flags: ${{ inputs.pytest_coverage_flags }}
pytest_markers: ${{ matrix.config.suite }}
Expand Down Expand Up @@ -543,11 +520,8 @@ jobs:
python_version: ${{ matrix.python-version }}
pipeline_mode: ${{ inputs.pipeline_mode }}
install_jax: ${{ contains(matrix.config.device, 'jax') }}
jax_version: ${{ inputs.jax_version }}
install_tensorflow: ${{ contains(matrix.config.device, 'tf') }}
tensorflow_version: ${{ inputs.tensorflow_version }}
install_pytorch: ${{ contains(matrix.config.device, 'torch') }}
pytorch_version: ${{ inputs.pytorch_version }}
install_pennylane_lightning_master: false
pytest_test_directory: pennylane/devices/tests
pytest_coverage_flags: ${{ inputs.pytest_coverage_flags }}
Expand Down
67 changes: 67 additions & 0 deletions .github/workflows/tests.yml
Expand Up @@ -9,6 +9,9 @@ concurrency:
group: unit-tests-${{ github.ref }}
cancel-in-progress: true

env:
DEPS_BRANCH: bot/stable-deps-update

jobs:
tests:
uses: ./.github/workflows/interface-unit-tests.yml
Expand All @@ -24,3 +27,67 @@ jobs:
&& !contains(github.event.pull_request.labels.*.name, 'ci:run-full-test-suite')
|| false
}}
upload-stable-deps:
needs: tests
runs-on: ubuntu-latest
if: ${{ github.event_name == 'push' }}
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-tags: true
sparse-checkout: .github

- name: Prepare local repo
run: |
git fetch
git config user.name "GitHub Actions Bot"
git config user.email "<>"
if git ls-remote --exit-code origin "refs/heads/${{ env.DEPS_BRANCH }}"; then
git checkout "${{ env.DEPS_BRANCH }}"
git rebase origin/master
else
git checkout master
git checkout -b "${{ env.DEPS_BRANCH }}"
fi
rm -f .github/stable/*.txt
- name: Download artifacts
uses: actions/download-artifact@v4
with:
pattern: frozen-*
path: .github/stable/
merge-multiple: true

- name: Determine if changes have been made
id: changed
run: |
echo "has_changes=$(git status --porcelain | wc -l | awk '{print $1}')" >> $GITHUB_OUTPUT
- name: Stage changes
if: steps.changed.outputs.has_changes != '0'
run: |
git add .github/stable/
git commit -m "Update changed dependencies"
git push -f --set-upstream origin "${{ env.DEPS_BRANCH }}"
# Create PR to master
- name: Create pull request
if: steps.changed.outputs.has_changes != '0'
uses: repo-sync/pull-request@v2
with:
source_branch: "${{ env.DEPS_BRANCH }}"
destination_branch: "master"
github_token: "${{ secrets.GITHUB_TOKEN }}"
pr_title: "Update stable dependency files"
pr_body: |
Automatic update of stable requirement files to snapshot valid python environments.
Because bots are not able to trigger CI on their own, please do so by pushing an empty commit to this branch using the following command:
```
git commit --allow-empty -m 'trigger ci'
```
pr_allow_empty: false
pr_draft: false
pr_reviewer: "timmysilv"

0 comments on commit 5f750f0

Please sign in to comment.