Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/scripts/update_py_deps.py
3987 views
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
raise FileNotFoundError(f"{requirements_file} not found")
19
20
print(f"Checking {requirements_file}")
21
22
# Parse current requirements preserving original format
23
current_lines = requirements_file.read_text().strip().split("\n")
24
packages = [] # (original_line, package_name_with_extras, package_name_normalized)
25
for line in current_lines:
26
line = line.strip()
27
if line and not line.startswith("#") and "==" in line:
28
name_with_extras, version = line.split("==", 1)
29
# Normalize: remove extras for pip queries
30
name_normalized = name_with_extras.split("[")[0].lower()
31
packages.append((line, name_with_extras, name_normalized))
32
33
with tempfile.TemporaryDirectory() as tmpdir:
34
venv_dir = Path(tmpdir) / "venv"
35
36
# Create virtual environment
37
print("Creating temporary virtual environment...")
38
subprocess.run(
39
[sys.executable, "-m", "venv", str(venv_dir)],
40
check=True,
41
capture_output=True,
42
)
43
44
pip = venv_dir / "bin" / "pip"
45
46
# Upgrade pip first
47
subprocess.run(
48
[str(pip), "install", "-q", "--upgrade", "pip"],
49
check=True,
50
capture_output=True,
51
)
52
53
# Install packages (with extras) to let pip resolve versions
54
install_names = [p[1] for p in packages] # name_with_extras
55
print(f"Installing {len(install_names)} packages...")
56
result = subprocess.run(
57
[str(pip), "install", "-q"] + install_names,
58
capture_output=True,
59
text=True,
60
)
61
if result.returncode != 0:
62
raise RuntimeError(f"Error installing packages:\n{result.stderr}")
63
64
# Get installed versions
65
result = subprocess.run(
66
[str(pip), "list", "--format=json"],
67
capture_output=True,
68
text=True,
69
check=True,
70
)
71
installed = {pkg["name"].lower(): pkg["version"] for pkg in json.loads(result.stdout)}
72
73
# Update versions in original lines
74
updated_lines = []
75
updates = []
76
for orig_line, name_with_extras, name_normalized in packages:
77
old_version = orig_line.split("==")[1]
78
new_version = installed.get(name_normalized)
79
80
if new_version and new_version != old_version:
81
updates.append((name_with_extras, old_version, new_version))
82
updated_lines.append(f"{name_with_extras}=={new_version}")
83
print(f" {name_with_extras}: {old_version} -> {new_version}")
84
else:
85
updated_lines.append(orig_line)
86
87
if not updates:
88
print("\nAll packages are up to date!")
89
return
90
91
# Rebuild file preserving non-package lines
92
new_content = []
93
pkg_idx = 0
94
for line in current_lines:
95
stripped = line.strip()
96
if stripped and not stripped.startswith("#") and "==" in stripped:
97
new_content.append(updated_lines[pkg_idx])
98
pkg_idx += 1
99
else:
100
new_content.append(line)
101
102
requirements_file.write_text("\n".join(new_content) + "\n")
103
print(f"\nUpdated {len(updates)} package(s)")
104
print("\nNow run: bazel run //py:requirements.update")
105
106
107
if __name__ == "__main__":
108
main()
109
110