File size: 1,313 Bytes
9f075f3 1eb60d5 9f075f3 1eb60d5 9f075f3 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | """用 3.8 的语法版本解析全仓 .py,判断「Python 3.8 兼容」是真声明还是口号。
只查语法(ast.parse 的 feature_version),不查运行时 API:3.8 上被移除/新增的标准库
行为差异(如 dict 顺序、zoneinfo)无法靠语法发现,那一层仍要靠真机 CI。
"""
from pathlib import Path
import ast
import os
import sys
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
SKIP_DIRS = {".git", "__pycache__", ".venv", "venv", "build", "dist", "_shots"}
TARGET = (3, 8)
def main():
bad = []
total = 0
for base, dirs, files in os.walk(ROOT):
dirs[:] = [d for d in dirs if d not in SKIP_DIRS]
for name in files:
if not name.endswith(".py"):
continue
path = os.path.join(base, name)
total += 1
try:
src = Path(path).read_text(encoding="utf-8")
ast.parse(src, filename=path, feature_version=TARGET)
except SyntaxError as exc:
bad.append((os.path.relpath(path, ROOT), exc.lineno, exc.msg))
print("parsed=%d py38_syntax_failures=%d" % (total, len(bad)))
for row in bad[:20]:
print(" FAIL %s:%s %s" % row)
return 1 if bad else 0
if __name__ == "__main__":
sys.exit(main())
|