Skip to content

Commit 375f30f

Browse files
committed
feat(version-scanner): refine python version checks and document boundary logic
1 parent 387abe0 commit 375f30f

2 files changed

Lines changed: 50 additions & 11 deletions

File tree

scripts/version_scanner/regex_config.yaml

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,23 @@ rules:
1717
examples:
1818
- "python_requires = '==3.7'"
1919
- "python_requires = '>=3.7'"
20+
- "python_requires = '>=3.7.0'"
2021
- "python_requires = '<=3.7'"
2122
- "python_requires = '>3.6'"
2223
- "python_requires = '<3.8'"
2324
rules:
2425
- |
25-
python_requires\s*=\s*['"]==3\.{minor}['"]
26+
python_requires\s*=\s*['"]==3\.{minor}(?:\.\d+)?['"]
2627
- |
27-
python_requires\s*=\s*['"]>=3\.{minor}['"]
28+
python_requires\s*=\s*['"]>=3\.{minor}(?:\.\d+)?['"]
2829
- |
29-
python_requires\s*=\s*['"]<=3\.{minor}['"]
30+
python_requires\s*=\s*['"]<=3\.{minor}(?:\.\d+)?['"]
31+
# Matches >3.6 (equivalent to >=3.7)
3032
- |
31-
python_requires\s*=\s*['"]>3\.{minor_minus_one}['"]
33+
python_requires\s*=\s*['"]>3\.{minor_minus_one}(?:\.\d+)?['"]
34+
# Matches <3.8 (equivalent to <=3.7)
3235
- |
33-
python_requires\s*=\s*['"]<3\.{minor_plus_one}['"]
36+
python_requires\s*=\s*['"]<3\.{minor_plus_one}(?:\.\d+)?['"]
3437
3538
- name: sys_version_info
3639
description: Finds sys.version_info checks in code.
@@ -46,15 +49,22 @@ rules:
4649
- "sys.version_info.minor <= 7"
4750
- "sys.version_info.minor > 6"
4851
- "sys.version_info.minor < 8"
52+
- "sys.version_info[1] == 7"
53+
- "sys.version_info[1] >= 7"
54+
- "sys.version_info[1] <= 7"
55+
- "sys.version_info[1] > 6"
56+
- "sys.version_info[1] < 8"
4957
rules:
5058
- |
5159
sys\.version_info\s*==\s*\(3,\s*{minor}\)
5260
- |
5361
sys\.version_info\s*>=\s*\(3,\s*{minor}\)
5462
- |
5563
sys\.version_info\s*<=\s*\(3,\s*{minor}\)
64+
# Matches sys.version_info > (3, 6) (equivalent to >=3.7)
5665
- |
5766
sys\.version_info\s*>\s*\(3,\s*{minor_minus_one}\)
67+
# Matches sys.version_info < (3, 8) (equivalent to <=3.7)
5868
- |
5969
sys\.version_info\s*<\s*\(3,\s*{minor_plus_one}\)
6070
- |
@@ -63,10 +73,24 @@ rules:
6373
sys\.version_info\.minor\s*>=\s*{minor}(?!\d)
6474
- |
6575
sys\.version_info\.minor\s*<=\s*{minor}(?!\d)
76+
# Matches sys.version_info.minor > 6 (equivalent to >=7)
6677
- |
6778
sys\.version_info\.minor\s*>\s*{minor_minus_one}(?!\d)
79+
# Matches sys.version_info.minor < 8 (equivalent to <=7)
6880
- |
6981
sys\.version_info\.minor\s*<\s*{minor_plus_one}(?!\d)
82+
- |
83+
sys\.version_info\[1\]\s*==\s*{minor}(?!\d)
84+
- |
85+
sys\.version_info\[1\]\s*>=\s*{minor}(?!\d)
86+
- |
87+
sys\.version_info\[1\]\s*<=\s*{minor}(?!\d)
88+
# Matches sys.version_info[1] > 6 (equivalent to >=7)
89+
- |
90+
sys\.version_info\[1\]\s*>\s*{minor_minus_one}(?!\d)
91+
# Matches sys.version_info[1] < 8 (equivalent to <=7)
92+
- |
93+
sys\.version_info\[1\]\s*<\s*{minor_plus_one}(?!\d)
7094
7195
- name: python_env_short
7296
description: Finds short python environment names often used in tox or nox.
@@ -99,4 +123,16 @@ rules:
99123
- |
100124
Python{major}{minor}(?!\d)
101125
126+
- name: dependency_requirement
127+
description: Finds standard dependency requirement formats (e.g., protobuf==3.7).
128+
examples:
129+
- "protobuf==3.7"
130+
- "protobuf>=3.7"
131+
- "protobuf<=3.7"
132+
- "protobuf~=3.7"
133+
- "protobuf!=3.7"
134+
rules:
135+
- |
136+
{name}\s*(?:==|>=|<=|~=|!=)\s*{version}
137+
102138

scripts/version_scanner/tests/unit/test_version_scanner.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,6 @@ def test_main_package_file_permission_error(tmp_path, capsys):
227227
package_file = tmp_path / "packages.txt"
228228
package_file.write_text("packages/pkg_a")
229229

230-
import sys
231230
test_args = ["version_scanner.py", "-d", "python", "-v", "3.7", "--package-file", str(package_file)]
232231

233232
real_open = open
@@ -246,7 +245,6 @@ def side_effect(file, *args, **kwargs):
246245
captured = capsys.readouterr()
247246
assert "Error: Permission denied reading package file" in captured.err
248247
def test_main_package_file_not_found(capsys):
249-
import sys
250248
test_args = ["version_scanner.py", "-d", "python", "-v", "3.7", "--package-file", "non_existent_file.txt"]
251249

252250
with patch("sys.argv", test_args):
@@ -323,7 +321,6 @@ def test_main_loads_ignore_from_script_dir(mock_scan, mock_load_ignore):
323321
mock_load_ignore.return_value = []
324322
mock_scan.return_value = []
325323

326-
import sys
327324
test_args = ["version_scanner.py", "-d", "python", "-v", "3.7"]
328325

329326
with mock.patch('sys.argv', test_args):
@@ -339,7 +336,8 @@ def test_main_loads_ignore_from_script_dir(mock_scan, mock_load_ignore):
339336

340337

341338
try:
342-
import googleapiclient
339+
# Ruff linter F401: Imported solely to detect Google API Client library presence for test skipping
340+
import googleapiclient # noqa: F401
343341
HAS_GOOGLE_API = True
344342
except ImportError:
345343
HAS_GOOGLE_API = False
@@ -407,8 +405,8 @@ def test_regex_examples_from_config():
407405

408406
rules_list = config.get("rules", [])
409407

410-
# Variables for interpolation (simulate Python 3.7)
411-
vars = {
408+
# Base variables for interpolation (simulate target version 3.7)
409+
base_vars = {
412410
"major": "3",
413411
"minor": "7",
414412
"version": "3.7",
@@ -424,6 +422,11 @@ def test_regex_examples_from_config():
424422
if not examples or not templates:
425423
continue
426424

425+
# Resolve target dependency name based on applies_to metadata, falling back to protobuf
426+
applies_to = rule_group.get("applies_to", [])
427+
dep_name = applies_to[0] if applies_to else "protobuf"
428+
vars = {**base_vars, "name": dep_name}
429+
427430
compiled_patterns = []
428431
for template in templates:
429432
try:

0 commit comments

Comments
 (0)