Skip to content

Commit e791f86

Browse files
committed
[build] use bazel to update python requirements
1 parent 1a68412 commit e791f86

File tree

5 files changed

+129
-83
lines changed

5 files changed

+129
-83
lines changed

.github/workflows/pre-release.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,10 @@ jobs:
129129
run: git commit -m "update selenium manager versions"
130130
- name: Update Maven dependency versions
131131
run: ./go java:update
132-
- name: Commit Maven version updates
133-
run: git commit -m "update maven dependency versions"
132+
- name: Update Python dependency versions
133+
run: ./go py:update
134+
- name: Commit version updates
135+
run: git commit -m "update dependency versions"
134136
- name: Update Authors file
135137
run: ./go authors
136138
- name: Commit Authors updates

Rakefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,14 @@ namespace :py do
667667
@git.add(conf)
668668
end
669669

670+
desc 'Update Python dependencies'
671+
task :update do
672+
Bazel.execute('run', [], '//scripts:update_py_deps')
673+
Bazel.execute('run', [], '//py:requirements.update')
674+
@git.add('py/requirements.txt')
675+
@git.add('py/requirements_lock.txt')
676+
end
677+
670678
namespace :test do
671679
desc 'Python unit tests'
672680
task :unit do

scripts/BUILD.bazel

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ py_binary(
3333
srcs = ["update_copyright.py"],
3434
)
3535

36+
py_binary(
37+
name = "update_py_deps",
38+
srcs = ["update_py_deps.py"],
39+
)
40+
3641
java_binary(
3742
name = "google-java-format",
3843
jvm_flags = [

scripts/update_py_dependencies.sh

Lines changed: 0 additions & 81 deletions
This file was deleted.

scripts/update_py_deps.py

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#!/usr/bin/env python
2+
3+
import json
4+
import subprocess
5+
import sys
6+
import tempfile
7+
from pathlib import Path
8+
9+
# Updates py/requirements.txt with latest compatible versions using pip
10+
# Run with: bazel run //scripts:update_py_deps
11+
12+
13+
def main():
14+
script_dir = Path(__file__).resolve().parent
15+
requirements_file = script_dir.parent / "py" / "requirements.txt"
16+
17+
if not requirements_file.exists():
18+
print(f"Error: {requirements_file} not found")
19+
return
20+
21+
print(f"Checking {requirements_file}")
22+
23+
# Parse current requirements preserving original format
24+
current_lines = requirements_file.read_text().strip().split("\n")
25+
packages = [] # (original_line, package_name_with_extras, package_name_normalized)
26+
for line in current_lines:
27+
line = line.strip()
28+
if line and not line.startswith("#") and "==" in line:
29+
name_with_extras, version = line.split("==", 1)
30+
# Normalize: remove extras for pip queries
31+
name_normalized = name_with_extras.split("[")[0].lower()
32+
packages.append((line, name_with_extras, name_normalized))
33+
34+
with tempfile.TemporaryDirectory() as tmpdir:
35+
venv_dir = Path(tmpdir) / "venv"
36+
37+
# Create virtual environment
38+
print("Creating temporary virtual environment...")
39+
subprocess.run(
40+
[sys.executable, "-m", "venv", str(venv_dir)],
41+
check=True,
42+
capture_output=True,
43+
)
44+
45+
pip = venv_dir / "bin" / "pip"
46+
47+
# Upgrade pip first
48+
subprocess.run(
49+
[str(pip), "install", "-q", "--upgrade", "pip"],
50+
check=True,
51+
capture_output=True,
52+
)
53+
54+
# Install packages (with extras) to let pip resolve versions
55+
install_names = [p[1] for p in packages] # name_with_extras
56+
print(f"Installing {len(install_names)} packages...")
57+
result = subprocess.run(
58+
[str(pip), "install", "-q"] + install_names,
59+
capture_output=True,
60+
text=True,
61+
)
62+
if result.returncode != 0:
63+
print(f"Error installing packages:\n{result.stderr}")
64+
return
65+
66+
# Get installed versions
67+
result = subprocess.run(
68+
[str(pip), "list", "--format=json"],
69+
capture_output=True,
70+
text=True,
71+
check=True,
72+
)
73+
installed = {
74+
pkg["name"].lower(): pkg["version"] for pkg in json.loads(result.stdout)
75+
}
76+
77+
# Update versions in original lines
78+
updated_lines = []
79+
updates = []
80+
for orig_line, name_with_extras, name_normalized in packages:
81+
old_version = orig_line.split("==")[1]
82+
new_version = installed.get(name_normalized)
83+
84+
if new_version and new_version != old_version:
85+
updates.append((name_with_extras, old_version, new_version))
86+
updated_lines.append(f"{name_with_extras}=={new_version}")
87+
print(f" {name_with_extras}: {old_version} -> {new_version}")
88+
else:
89+
updated_lines.append(orig_line)
90+
91+
if not updates:
92+
print("\nAll packages are up to date!")
93+
return
94+
95+
# Rebuild file preserving non-package lines
96+
new_content = []
97+
pkg_idx = 0
98+
for line in current_lines:
99+
stripped = line.strip()
100+
if stripped and not stripped.startswith("#") and "==" in stripped:
101+
new_content.append(updated_lines[pkg_idx])
102+
pkg_idx += 1
103+
else:
104+
new_content.append(line)
105+
106+
requirements_file.write_text("\n".join(new_content) + "\n")
107+
print(f"\nUpdated {len(updates)} package(s)")
108+
print("\nNow run: bazel run //py:requirements.update")
109+
110+
111+
if __name__ == "__main__":
112+
main()

0 commit comments

Comments
 (0)