Skip to content

Commit

Permalink
Improve how we manage which PDM to use
Browse files Browse the repository at this point in the history
Move our PDM version pin to a separate file. This both makes it easier
to manage updates to the same and also allows the pinned version to be
usable outside of the venv_sync script. Add a simple script to update
version pins in this file. Teach venv_upgrade to use this to update the
PDM version pin in addition to updating the PDM lock file. Also, modify
venv_sync to tell PDM to not complain about newer versions.
  • Loading branch information
mwoehlke-kitware committed Jan 8, 2025
1 parent f164831 commit 7d1d867
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 10 deletions.
1 change: 1 addition & 0 deletions setup/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ exports_files([
"mac/source_distribution/Brewfile-maintainer-only",
"python/pdm.lock",
"python/pyproject.toml",
"python/requirements.txt",
"ubuntu/binary_distribution/packages-jammy.txt",
"ubuntu/source_distribution/packages-jammy.txt",
"ubuntu/source_distribution/packages-jammy-clang.txt",
Expand Down
12 changes: 12 additions & 0 deletions setup/python/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# This file describes does NOT describe the requirements for Drake itself, but
# for setting up the Python virtual environment that Drake will manage. It is
# used by Drake's @python, and also when preparing a virtual environment to
# support a Drake installation.
#
# Specific version pins in this file are updated automatically by
# tools/workspace/python/venv_upgrade.

# TODO(jeremy.nimmer) Ideally, we also would pin all of the dependencies of
# PDM here, but it's not obvious to me how to do that in a way which is easy to
# upgrade/re-pin over time.
pdm==2.22.0
10 changes: 7 additions & 3 deletions tools/workspace/python/repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,13 @@ def _prepare_venv(repo_ctx, python):
if os_name != "mac os x":
return python

# Locate the lock file and mark it to be monitored for changes.
pylock = repo_ctx.path(Label("@drake//setup:python/pdm.lock")).realpath
repo_ctx.watch(pylock)
# Locate lock files and mark them to be monitored for changes.
requirements = repo_ctx.path(
Label("@drake//setup:python/requirements.txt"),
).realpath
pdmlock = repo_ctx.path(Label("@drake//setup:python/pdm.lock")).realpath
repo_ctx.watch(requirements)
repo_ctx.watch(pdmlock)

# Choose which dependencies to install.
if repo_ctx.attr.requirements_flavor == "test":
Expand Down
43 changes: 43 additions & 0 deletions tools/workspace/python/update_requirements.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env python3

import json
import sys
import urllib.request


def get_latest_version(name):
r = urllib.request.urlopen(f'https://pypi.org/pypi/{name}/json')
d = json.loads(r.read())
return d['info']['version']


def update_requirements(requirements_path):
updated = False

lines = []
with open(requirements_path, 'r') as f:
for line in f:
line = line.strip()

if not line.startswith('#') and '==' in line:
name, current = line.split('==')
latest = get_latest_version(name)
if latest != current:
line = f'{name}=={latest}'
updated = True

lines.append(line)

if updated:
with open(requirements_path, 'w') as f:
f.write('\n'.join(lines))
print(requirements_path)


def main(args):
for p in args:
update_requirements(p)


if __name__ == '__main__':
main(sys.argv[1:])
14 changes: 8 additions & 6 deletions tools/workspace/python/venv_sync
Original file line number Diff line number Diff line change
Expand Up @@ -53,32 +53,34 @@ fi
# Place the venv(s) in a sibling directory to the output base. That should be a
# suitable disk location for build artifacts, but without polluting the actual
# output base that Bazel owns.
readonly drake_root="$(cd "$(dirname $0)/../../.." && pwd)"
readonly bazel_output_base="$(cd "${repository}/../.." && pwd)"
readonly drake_python="${bazel_output_base}.drake_python"
mkdir -p "${drake_python}"

# Install PDM into a virtual environment. We segregate PDM from the environment
# it is managing, so that changes to the managed environment cannot break PDM.
readonly setup="${drake_root}/setup/python"
readonly venv_pdm="${drake_python}/venv.pdm"
mkvenv "${venv_pdm}"
# TODO(jeremy.nimmer) Ideally, we also would pin all of the dependencies of
# PDM here, but it's not obvious to me how to do that in a way which is easy to
# upgrade/re-pin over time.
"${venv_pdm}/bin/pip" install -U pdm==2.22.0
"${venv_pdm}/bin/pip" install -U -r "${setup}/requirements.txt"

# Don't nag about new versions of PDM; we'll update the above pin when we want
# to use something newer, and otherwise want to use the pinned version, so
# being informed about newer versions is just noise.
export PDM_CHECK_UPDATE=0

# Prepare the PDM "project directory".
readonly drake_root="$(cd "$(dirname $0)/../../.." && pwd)"
readonly setup="${drake_root}/setup/python"
readonly project="${drake_python}/project"
mkdir -p "${project}"
ln -nsf "${setup}/pyproject.toml" "${project}/pyproject.toml"
ln -nsf "${setup}/pdm.lock" "${project}/pdm.lock"

# Don't nag about new versions of PDM; venv_upgrade will check for those.
# Aside from that, we want to use the pinned version, so being informed about
# newer versions is just noise.
export PDM_CHECK_UPDATE=0

# Prepare the venv that will hold Drake's requirements.
readonly venv_drake="${drake_python}/venv.drake"
mkvenv "${venv_drake}"
Expand Down
13 changes: 12 additions & 1 deletion tools/workspace/python/venv_upgrade
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ cd "$(dirname $0)/../../.."
readonly drake_python="$(bazel info output_base).drake_python"
readonly project="${drake_python}/project"
readonly venv_pdm="${drake_python}/venv.pdm"
readonly python="${venv_pdm}/bin/python"
readonly workspace="$(pwd)/tools/workspace/python"

# If committing, check that the working tree is clean (enough). Note that the
# lock file is ignored.
Expand All @@ -47,11 +49,20 @@ readonly venv_pdm="${drake_python}/venv.pdm"
# Ensure venv exists.
bazel fetch @python --force

# Determine if PDM itself is up to date; if not, update its pin.
readonly venv_requirements="./setup/python/requirements.txt"
files_to_commit+=( "$(
"${python}" "${workspace}/update_requirements.py" "${venv_requirements}"
)" )

# Ensure venv is up to date (e.g. if the previous step updated PDM).
bazel fetch @python

# Remove and recreate the lock file.
readonly lockfile="./setup/python/pdm.lock"
rm -f "${lockfile}"
"${venv_pdm}/bin/pdm" lock -p "${project}" -L "${lockfile}"
files_to_commit+=($(git diff --name-only HEAD -- "${lockfile}"))
files_to_commit+=( "$(git diff --name-only HEAD -- "${lockfile}")" )

# If committing, do the commit.
if [ -n "${commit}" ]; then
Expand Down

0 comments on commit 7d1d867

Please sign in to comment.