Skip to content

chore: migrate dependency management to uv#507

Open
rpocase wants to merge 5 commits into
canonical:mainfrom
rpocase:20260626-migrate-deps-to-pyproject
Open

chore: migrate dependency management to uv#507
rpocase wants to merge 5 commits into
canonical:mainfrom
rpocase:20260626-migrate-deps-to-pyproject

Conversation

@rpocase

@rpocase rpocase commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator

PR Checklist

To ease the process of reviewing your PR, do make sure to complete the following checklist before submitting a pull
request.

  • I have added unit tests to cover the new behavior under ``tests/unit_tests/```
  • I have run tox -e format locally to automatically format my code before submitting
  • I have run tox locally ensuring that it passes before submitting
  • [-] (if applicable) I have added a reference to issues that this PR relates to in the PR message (Refs GH-1234, Fixes GH-1234)
  • My commits are atomic and follow the convetional commit message format (https://www.conventionalcommits.org/en/v1.0.0/)

Otherwise, please leave the PR as a draft to indicate that it is still a work in progress.

Description

this change migrates dependencies to be properly managed by uv instead of specified in requirements files,
upgrades mypy, and fixes newly found type hinting issues. this is in preparation for upgrading
openstack-sdk as netiface is orphaned and should be migrated to netiface2

Additional Context and Relevant Issues

this was triggered in part because running mypy was failing because of a missing typed-ast package.
at the same time, i've upgraded mypy and resolved all new type hinting issues.

Test Steps

N/A? i think integration tests should be run, but i don't have a proper setup to facilitate this

@rpocase
rpocase requested a review from Copilot June 26, 2026 15:17
@rpocase
rpocase force-pushed the 20260626-migrate-deps-to-pyproject branch from 4b68ff4 to 6850dfe Compare June 26, 2026 15:22
@rpocase rpocase changed the title chore: migrate to UV chore: migrate dependency management to uv Jun 26, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Migrates the project from legacy requirements/setup.cfg packaging to a pyproject.toml-driven build (Hatchling) and dependency management aligned with uv, while updating type hints/signatures to satisfy a newer mypy.

Changes:

  • Replaced setup.py/setup.cfg + requirements*.txt with PEP 621 metadata and extras in pyproject.toml (Hatchling backend).
  • Updated tox, Read the Docs config, and a CI workflow step to install dependencies via extras/uv instead of requirements files.
  • Adjusted several cloud/instance method signatures to accept **kwargs and tightened example type annotations for mypy.

Reviewed changes

Copilot reviewed 18 out of 19 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tox.ini Switches tox deps to install via project extras rather than requirements files; updates lint/typecheck targets.
test-requirements.txt Removes legacy test requirements list (moved into pyproject.toml extras).
setup.py Removes legacy setuptools entry point.
setup.cfg Removes legacy package metadata and dependency declarations.
requirements.txt Removes legacy “-e .” requirements indirection.
pyproject.toml Adds PEP 621 project metadata, dependencies, optional extras, and tool configs; switches build backend to Hatchling.
pycloudlib/openstack/instance.py Updates method signature to accept **kwargs for interface compatibility.
pycloudlib/oci/cloud.py Adds **kwargs to selected APIs for signature compatibility.
pycloudlib/lxd/instance.py Adds **kwargs to lifecycle methods; threads get_pty through _run_command.
pycloudlib/lxd/cloud.py Adds **kwargs to snapshot signature for interface compatibility.
pycloudlib/gce/instance.py Adds **kwargs to wait_for_delete signature for interface compatibility.
pycloudlib/ec2/cloud.py Adds **kwargs to snapshot signature for interface compatibility.
examples/oracle/oracle-cluster-demo.py Uses Optional[str] for nullable parameters to satisfy mypy.
examples/ibm_classic.py Uses Optional[str] for nullable parameters to satisfy mypy.
docs/requirements.txt Removes legacy docs requirements list (moved into pyproject.toml extras).
ci-requirements.txt Removes legacy CI requirements list.
.readthedocs.yaml Switches RTD install method to uv and uses the docs extra.
.github/workflows/version_check.yaml Installs uv and uses it to install packaging for version checking.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pyproject.toml
Comment thread tox.ini
Comment thread .readthedocs.yaml
@rpocase
rpocase force-pushed the 20260626-migrate-deps-to-pyproject branch 3 times, most recently from 5eaab84 to cef1487 Compare June 26, 2026 15:57
@rpocase

rpocase commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator Author

@blackboxsw if you have a moment

@rpocase rpocase mentioned this pull request Jun 26, 2026
4 tasks
@rpocase
rpocase enabled auto-merge (rebase) June 26, 2026 16:34

@holmanb holmanb left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why uv rather than pip?

@rpocase
rpocase disabled auto-merge June 26, 2026 17:29
@rpocase
rpocase force-pushed the 20260626-migrate-deps-to-pyproject branch from cef1487 to 5260eb3 Compare June 26, 2026 17:58
@rpocase

rpocase commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator Author

Why uv rather than pip?

  1. i misread the repo and thought it was using uv to manage installation but wasn't using pyproject.toml for dependency management
  2. more modern tooling that is become increasingly pervasive
  3. we should look at integrating AGENTS.md and providing a sandboxing environment. i would go with workshops. the only supported path forward to easily bootstrap is with the uv plugin. it would have to be a lot more customized if we stuck with pip

@rpocase
rpocase requested a review from blackboxsw June 26, 2026 21:42

@blackboxsw blackboxsw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thank you @rpocase for this proposal this looks like a good direction to me. Let's iron out a few of these concerns before moving forward please.

  1. I think we are missing changes to docs/Makefile related to pip install -rrequirements.txt which no longer exists. cd docs; make deps fails.2. I'd like to use your separate commit messages as the produce more useful context for each commit, but the uv.lock file is introduced in the first commit and removed in the third commit. Can we drop that delta from both first as last commits

  2. I left inline comments about changes in the supported floor version of dependencies, can we ensure we aren't getting a lower/older supported minimum version than we already had in main?

  3. inline comment about using github issues instead of a launchpad project that doesn't exist.

  4. I'm seeing with CI that is erroring at the moment with this uv branch on 'new prs' is the following lint errors:```
    pycloudlib/azure/instance.py:288: error: Unused "type: ignore" comment [unused-ignore]
    pycloudlib/azure/instance.py:311: error: Unused "type: ignore" comment [unused-ignore]
    pycloudlib/azure/instance.py:362: error: Unused "type: ignore" comment [unused-ignore]


Note: I can confirm though both integration tests in ubuntu-pro-client and in cloud-init that this changeset doesn't introduce issues with CICD there.

Also, the general dep installation improvement time in cold/empty cache is a significant improvement:
  - uv-based cold : ~13.5 seconds
  - uv-based warm: ~1.5 seconds
  - pip-based cold:  ~64 seconds
  - pip-based warm: ~43 seconds

I like the improvements this represents for the project. thank you.

Comment thread pyproject.toml Outdated
Comment thread pyproject.toml
Comment thread pyproject.toml Outdated
Comment thread pyproject.toml
Comment on lines +67 to +68
"types-mock>=5.0.0",
"types-pyyaml>=6.0.12",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Now that we are unpinning specific versions, we should watch pycloudlib CI more often to ensure we aren't getting affected by changes in remote unpinnned dependencies. If this becomes a problem we can attempt to place a version ceiling to avoid external breaking changes where possible. I don't think we need a change to this PR, just an agreement to look at adding dependency ceilings if we start seeing breakage due to upstream external dependency changes.

Comment thread docs/index.rst Outdated
Comment thread pycloudlib/lxd/instance.py Outdated
@rpocase
rpocase force-pushed the 20260626-migrate-deps-to-pyproject branch 3 times, most recently from 25b0dfe to dce86a2 Compare July 9, 2026 21:20
Comment on lines +533 to +541
def _run_command(self, command, stdin, get_pty=False):
"""Run command in the instance."""
if self.execute_via_ssh:
return super()._run_command(command, stdin)
return super()._run_command(command, stdin, get_pty=get_pty)

if self.series == "xenial":
self._log.warning(MISSING_AGENT_MSG, "lxc exec")

return super()._run_command(command, stdin)
return super()._run_command(command, stdin, get_pty=get_pty)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@blackboxsw how do you want to handle this? this is another case where the superclass explicitly supports it and the subclass has broken the subclass contract.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@rpocase Sorry, I'm not getting what you mean here. The superclass explicitly supports exactly this same call signature with get_pty param. How is the subclass breaking that contract? I must be misreading something.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

the superclass supported the keyword argument, but the subclass didn't expose the argument. i wasn't sure if this was intentional or not.

@blackboxsw blackboxsw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

After testing with both ubuntu-pro-client and cloud-init integration tests I feel comfortable that this tooling update isn't going to negatively impact CI in either case.

Also integration test runs locally appear to work fine for new PRs in pycloudlib with these new workflow changes.

While generally I wouldn't want to replace tooling unless dependency feature deprecations are imminent or projects are becoming abandoned I do see an easy path toward other tooling integration with workshop as @rpocase mentioned (as well as faster dep install time uv vs pip). Given that pycloudlib import as set is being used so broadly by CPC, cloud-init and ubuntu-pro-client CICD, that time/setup saving adds up fairly quickly.

will follow up on get_ply and lxd

Comment thread pyproject.toml
Comment thread .github/workflows/ci.yaml Outdated

@blackboxsw blackboxsw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Additionally I think we need to:

  1. Adapt the deps target from docs/Makefile to avoid pip references to requirements.txt which is now deleted.
  2. drop *requirements.txt from MANIFEST.in

Comment thread pyproject.toml
Comment on lines +533 to +541
def _run_command(self, command, stdin, get_pty=False):
"""Run command in the instance."""
if self.execute_via_ssh:
return super()._run_command(command, stdin)
return super()._run_command(command, stdin, get_pty=get_pty)

if self.series == "xenial":
self._log.warning(MISSING_AGENT_MSG, "lxc exec")

return super()._run_command(command, stdin)
return super()._run_command(command, stdin, get_pty=get_pty)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@rpocase Sorry, I'm not getting what you mean here. The superclass explicitly supports exactly this same call signature with get_pty param. How is the subclass breaking that contract? I must be misreading something.

rpocase added 5 commits July 20, 2026 12:39
the current setup is unexpected given the test runner is using uv.
this migrates the setup to uv. mypy and some typed dependencies
needed to be upgrade due to messaging around "typed-ast" not
being installed with seemingly no workaround.
- Add [tool.uv] python-preference = "only-system" to pyproject.toml
  so uv never downloads a managed Python and always uses the system
  interpreter
- Add tox-uv to tox requires so tox uses uv as its venv/install backend
- Replace apt tox installs with astral-sh/setup-uv in all workflows
- Collapse separate py310/py312 CI jobs into a single matrix job that
  selects the Ubuntu runner (22.04/24.04) based on the target Python
  version, making the Python→runner mapping explicit and easy to extend
- Simplify version_check workflow: drop actions/setup-python and pip
  installs in favour of uv run --with packaging
the migration from launchpad to github did not correct the
issue tracker link.
migrating to mypy 2.x resulted in a larger amount of type
failures being detected. this resolves all outstanding type hinting
failures
this converts all tag based action checkouts to the latest corresponding
shasum.
@rpocase
rpocase force-pushed the 20260626-migrate-deps-to-pyproject branch from dce86a2 to 14ec0c1 Compare July 20, 2026 17:39
@rpocase

rpocase commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator Author

@blackboxsw latest push addresses the commit pins and ensures that the recent azure-network-mgmt pin stays in place

@blackboxsw blackboxsw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks @rpocase looks good with two exceptions:

  1. pinning correction on azure-mgmt-network
  2. I don't think we want to commit uv.lock to this project repo do we? I may be mistaken, but thought when you have a library you are building, you may not want to provide uv.lock because that library may be used in other environments which may be created in other releases of Ubuntu where the python versions of dependencies may differ from our upstream repo. Again, I may be mistaken as I haven't used uv too often with distributed libraries.

If you think we need to keep uv.lock, how do you envision cloud-init, cpc tests, ubuntu pro attempting to run those project test suites. do they perform a uv sync to get the same uv.lock version from pycloudlib prior to running tests?

The pinning suggestion doesn't matter for too long as I just put up #516 which may help drop this pin in favor of the new Azure SDK model-based hybrid requests. I'll rebase 516 after this PR lands to fix the pinning minor version and avoid delaying your work any longer.

Comment thread pyproject.toml
"azure-cli-core >= 2.21.0",
"azure-identity",
"azure-mgmt-compute >= 17",
"azure-mgmt-network <= 31",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This should be >= 16, < 31 not <= 31.

Suggested change
"azure-mgmt-network <= 31",
"azure-mgmt-network >=16, < 31",

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.

4 participants