Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CI: Utilize uv lockfile for reproducible test environments #6640

Merged
merged 18 commits into from
Dec 5, 2024

Conversation

danielhollas
Copy link
Collaborator

@danielhollas danielhollas commented Nov 25, 2024

This PR removes the requirement files in requirements/ folder and replaces them with a single universal lockfile uv.lock. "universal" in this case means that it contains resolved package versions for all supported python versions and operating systems. More on the uv lockfiles can be found in their docs: https://docs.astral.sh/uv/concepts/projects/layout/#the-lockfile

When modifying the dependencies in pyproject.toml, the lockfile needs to be updated by running

uv lock

(Note that using e.g. uv add, uv remove or uv sync updates the lockfile automatically)

This relative simplicity compared to the previous custom solution allows for much easier development and I could delete a lot of custom YAML in CI. To check whether the lockfile is up to date, one can simply run

uv lock --locked

This command is run automatically as a pre-commit hook whenever pyproject.toml is changed.

Note

Developers don't necessarily need to use the lockfile locally, nor are they required to have uv installed, unless they need to modify dependencies in pyproject.toml

Closes #6613

@danielhollas danielhollas changed the title WIP: See if we can use uv lockfile See if we can use uv lockfile Nov 28, 2024
In this implementation, the hook will only check
whether the lockfile is compatible with pyproject.toml,
it will not try to automatically update it, since that
should be decided by the developer.
- name: Install dependencies from uv lock
# NOTE: We're also asserting that the lockfile is up to date
if: ${{ inputs.from-lock == 'true' }}
run: uv sync --locked --extra pre-commit
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NOTE: By default we're installing with pre-commit optional dependencies (extras), which transitively includes other extras, see pyproject.toml I think this is the best solution to make things work for now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we add the extra all that includes all extra packages to make it more explicit that we check all of them? I am not sure if there is a scenario where we will change something that is not included in pre-commit, but it is also not super clear that we choose pre-commit here to include all extras. At least I would add a comment

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a comment for now. I agree this is not ideal, I have some ideas but want to keep them for a separate PR since there's a lot going on here already.

Note that if we wanted to always install all the extras, we could just pass the --all-extras parameter to uv. But that would (among others) install the whole jupyter stack which seems wasteful.

utils/dependency_management.py @aiidateam/dependency-manager
.github/workflows/dm.yml @aiidateam/dependency-manager
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file does not exist.

@danielhollas danielhollas marked this pull request as ready for review November 28, 2024 20:42
@danielhollas danielhollas changed the title See if we can use uv lockfile CI: Utilize uv lockfile for reproducible test environments Nov 28, 2024
@danielhollas
Copy link
Collaborator Author

@agoscinski @unkcpz I think this PR is mostly ready now, let me know what you think!

The only thing missing is developer documentation: I would suggest moving the Dependency Management Wiki article to the repo in a separate PR.

Copy link

codecov bot commented Nov 28, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 77.93%. Comparing base (ef60b66) to head (e62a2ef).
Report is 154 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6640      +/-   ##
==========================================
+ Coverage   77.51%   77.93%   +0.43%     
==========================================
  Files         560      563       +3     
  Lines       41444    41662     +218     
==========================================
+ Hits        32120    32464     +344     
+ Misses       9324     9198     -126     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@unkcpz
Copy link
Member

unkcpz commented Nov 29, 2024

The only thing missing is developer documentation: I would suggest moving the Dependency Management Wiki article to the repo in a separate PR.

Sure, go ahead with a separate PR, thanks!

@khsrali
Copy link
Contributor

khsrali commented Nov 29, 2024

@danielhollas nice, thanks a lot!
suppose I have an entry in my pyproject.toml as such:
'plumpy@git+https://github.com/khsrali/plumpy.git@allow-async-upload-download#egg=plumpy',

would this be understood and accepted by uv lock?

@danielhollas
Copy link
Collaborator Author

@khsrali I tried it and it works without a problem. :-)
btw: I don't think you need the #egg=plumpy part at the and of the URL, and uv strips it anyways.

Copy link
Member

@unkcpz unkcpz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unless they need to modify dependencies in pyproject.toml

I don't understand how this will work. I think if we run uv lock from different machine, the lock file is generated using the environment where the command is run. Which means two people will have two different lock file generated. Is this leading to large number of lines change?

@@ -96,15 +64,15 @@ jobs:
python-version: ${{ matrix.python-version }}

- name: Setup environment
run: .github/workflows/setup.sh
run: source .venv/bin/activate && .github/workflows/setup.sh
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this .venv created from?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is created by uv sync automatically in the install-aiida-core action above.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we write it as comment or like this?

Suggested change
run: source .venv/bin/activate && .github/workflows/setup.sh
run: uv venv && source .venv/bin/activate && .github/workflows/setup.sh

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wrote a comment about this both here and in actions/install-aiida-core/action.yml. See 7959c4d

@danielhollas
Copy link
Collaborator Author

I think if we run uv lock from different machine, the lock file is generated using the environment where the command is run.

uv should generate a universal lock file independent of your current python version or OS. At least that is my understanding, would be good if you can verify. I have generated the lock here on Linux and Python 3.12

Also you can try using the lock file I generated by running uv sync. It should work regardless of your python version.

@danielhollas
Copy link
Collaborator Author

When merging main into this branch, the lock needed to be updated. Just to illustrate, here's how the failed pre-commit hook looked`

pre-commit run -a check-uv-lock
Check uv lockfile up to date.............................................Failed
- hook id: check-uv-lock
- exit code: 2

Resolved 254 packages in 126ms
error: The lockfile at `uv.lock` needs to be updated, but `--locked` was provided. To update the lockfile, run `uv lock`.

Then all I needed to do is to run uv lock

uv lock
Resolved 254 packages in 152ms
Added execnet v2.1.1
Added pytest-xdist v3.6.1

Note, if we wanted, we can also update the lock automatically as part of the pre-commit hook to avoid the extra manual step?

@danielhollas
Copy link
Collaborator Author

I was thinking about similar thing with pip-compile,

Yeah, the previous solution using requirements.txt files was done with pip-compile, but as you pointed out, the major downside is that pip-compile does depend on the python version that you use to run it, so to properly update all the requirement files you'd need to install python versions 3.9-3.12.

@unkcpz
Copy link
Member

unkcpz commented Dec 2, 2024

Note, if we wanted, we can also update the lock automatically as part of the pre-commit hook to avoid the extra manual step?

Yes, I think this is better to avoid manual run of the pre-commit locally.

Copy link
Contributor

@agoscinski agoscinski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the work @danielhollas I think this is very useful. I needed some time to wrap my head around the changes. I am trying it out now in #6600

.github/workflows/test-install.yml Show resolved Hide resolved
@agoscinski
Copy link
Contributor

I had an issue with scipy, needed to be 1.14.1 for the python 3.13 but uv lock and uv lock --upgrade did not upgrade even though my local version was 1.14.1, then with uv lock --upgrade-package scipy==1.14.1 it finally told me that it does not upgrade because scipy==1.14.1 does not support python 3.9. So I needed to specify the scipy version for the python 3.13 separately. I would say it worked very well.

Copy link
Contributor

@agoscinski agoscinski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some minor changes to add doc here and there. Thanks for the work! I think minor changes + a rebase and then we can merge

- name: Install dependencies from uv lock
# NOTE: We're also asserting that the lockfile is up to date
if: ${{ inputs.from-lock == 'true' }}
run: uv sync --locked --extra pre-commit
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we add the extra all that includes all extra packages to make it more explicit that we check all of them? I am not sure if there is a scenario where we will change something that is not included in pre-commit, but it is also not super clear that we choose pre-commit here to include all extras. At least I would add a comment

.github/actions/install-aiida-core/action.yml Show resolved Hide resolved
@@ -96,15 +64,15 @@ jobs:
python-version: ${{ matrix.python-version }}

- name: Setup environment
run: .github/workflows/setup.sh
run: source .venv/bin/activate && .github/workflows/setup.sh
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we write it as comment or like this?

Suggested change
run: source .venv/bin/activate && .github/workflows/setup.sh
run: uv venv && source .venv/bin/activate && .github/workflows/setup.sh

issue-number: ${{ github.event.number }}
body: |
Please update the requirements/ files to ensure that they
are consistent with the dependencies specified in the 'pyproject.toml' file.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel bad deleting this, but maintaining this seems to me me not worth the effort. Especially, since we don't update dependencies frequently.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you feel bad? None of this is needed now when we have the lockfile, no?

@danielhollas
Copy link
Collaborator Author

@agoscinski thanks for the review! I've merged in main and added more comments, should be good to go.

There are definitely things that could be improved, but I'll save that for a followup.

@khsrali
Copy link
Contributor

khsrali commented Dec 4, 2024

@danielhollas , stupid question:
do we need to list uv as dependency in pyproject.toml?

@danielhollas
Copy link
Collaborator Author

do we need to list uv as dependency in pyproject.toml?

Not really, in the same way that you don't list pip in your dependencies. :-) uv is the installer so it needs to exist outside of the project.

Copy link
Contributor

@agoscinski agoscinski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks again for the work @danielhollas

@unkcpz
Copy link
Member

unkcpz commented Dec 5, 2024

I remove the outdated "check-requirement" CI restriction. So it is able to merge.
This is a great CI improvement, thanks a lot for the effort! @danielhollas

@unkcpz unkcpz merged commit 04cc344 into aiidateam:main Dec 5, 2024
22 checks passed
@danielhollas danielhollas deleted the uv-lock branch December 5, 2024 17:21
@unkcpz
Copy link
Member

unkcpz commented Dec 5, 2024

It seems other CI actions are failed after merging this. I'll have a look later.

@unkcpz
Copy link
Member

unkcpz commented Dec 5, 2024

After this PR, the AEP https://github.com/aiidateam/AEP/blob/master/002_dependency_management/readme.md is outdated. @danielhollas would you mind to update it to sync it (or put a link in the AEP point to the doc) with the developer documentation you are preparing?

@GeigerJ2
Copy link
Contributor

GeigerJ2 commented Dec 6, 2024

Sorry, @danielhollas, for ignoring this... been busy with some other stuff. I see the rest of the aiida-core office took over. Thanks for the work! <3

@danielhollas
Copy link
Collaborator Author

No worries at all, I was mostly tagging everybody for visibility. :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

CI: Consider using uv's lock file instead of requirement files
5 participants