fix: pass the installer's own lint gate

install.py held a local it never read and, since the registry path
rules, a loop variable shadowing the platform module, so the py38
ruff gate the installer is held to failed. Both are fixed, and the
suite reads the two rules from the syntax tree since CI has no ruff.
This commit is contained in:
Abdessamad Derraz committed 2026-10-18 05:18:08 +02:00
1 parent e04646d67a
commit 5a32a42d25
4 files changed
+51 -6

No files matched your search

+1 -1
View File
@@ -8,7 +8,7 @@ param(
$ErrorActionPreference = "Stop"
$defaultInstallUrl = "https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
$defaultInstallSha256 = "dc6b428278a4352923c19ddcf055fd994aac1df77f35cb1d097e8f4c5d887ae1"
$defaultInstallSha256 = "973e116ab59e233cd4fe5ebb77d4973bc06013b22b6388e80d12fa1d61fb0c73"
$maximumInstallerBytes = 2MB
$installerExit = 0
$installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null }
+3 -4
View File
@@ -175,7 +175,6 @@ def _os_default_dests(os_type: str) -> dict[str, Path]:
home = Path.home()
if os_type == "windows":
profile = Path(os.environ.get("USERPROFILE", str(home)))
appdata = Path(os.environ.get("APPDATA", str(home / "AppData" / "Roaming")))
return {
# RetroArch's system directory defaults to <exe folder>\system
# (platform_win32.c), and its installer to C:\RetroArch-Win64.
@@ -904,11 +903,11 @@ def _rule_path(template: str) -> Path:
def _detect_by_path(os_type: str, found: list[tuple[str, Path]]) -> None:
"""Add what a registry path rule finds, for a platform not found yet."""
systems = ("linux", "windows") if os_type == "wsl" else (os_type,)
for rule_os, platform, path, bios in _PATH_RULES:
if rule_os not in systems or any(name == platform for name, _ in found):
for rule_os, platform_name, path, bios in _PATH_RULES:
if rule_os not in systems or any(name == platform_name for name, _ in found):
continue
if _rule_path(path).exists():
found.append((platform, _rule_path(bios or path)))
found.append((platform_name, _rule_path(bios or path)))
def detect_platforms(os_type: str) -> list[tuple[str, Path]]:
+1 -1
View File
@@ -18,7 +18,7 @@ esac
TEMP_INSTALLER=""
TEMP_DIRECTORY=""
DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
DEFAULT_INSTALL_SHA256="dc6b428278a4352923c19ddcf055fd994aac1df77f35cb1d097e8f4c5d887ae1"
DEFAULT_INSTALL_SHA256="973e116ab59e233cd4fe5ebb77d4973bc06013b22b6388e80d12fa1d61fb0c73"
MAX_INSTALLER_BYTES=2097152
cleanup() {
+46
View File
@@ -1151,6 +1151,52 @@ class InstallerStaysOnPython38AndTheStdlib(unittest.TestCase):
self.assertEqual(used, [])
def test_no_local_is_assigned_and_never_read(self):
"""ruff --select F in py38 mode is the installer's lint gate; an
unread `appdata` in _os_default_dests made it exit 1. The suite has
no ruff, so the rule is read from the syntax tree."""
import ast # noqa: PLC0415
tree = ast.parse((Path(__file__).resolve().parents[1] / "install.py").read_text())
unread = []
for func in ast.walk(tree):
if not isinstance(func, (ast.FunctionDef, ast.AsyncFunctionDef)):
continue
stored, loaded = {}, set()
for node in ast.walk(func):
if isinstance(node, ast.Name):
if isinstance(node.ctx, ast.Store):
stored.setdefault(node.id, node.lineno)
else:
loaded.add(node.id)
nested = {
n.id for inner in ast.walk(func) if inner is not func
and isinstance(inner, (ast.FunctionDef, ast.Lambda))
for n in ast.walk(inner) if isinstance(n, ast.Name)
}
unread += [
f"{func.name}:{line} {name}" for name, line in stored.items()
if name not in loaded | nested and not name.startswith("_")
and not any(
isinstance(g, (ast.Global, ast.Nonlocal)) and name in g.names
for g in ast.walk(func)
)
]
self.assertEqual(unread, [])
# Nor a module rebound: a loop variable named `platform` shadowed the
# platform module in _detect_by_path (F402).
modules = {
alias.asname or alias.name.split(".")[0]
for node in tree.body if isinstance(node, ast.Import)
for alias in node.names
}
rebound = sorted(
f"{node.id}:{node.lineno}" for node in ast.walk(tree)
if isinstance(node, ast.Name) and isinstance(node.ctx, ast.Store)
and node.id in modules
)
self.assertEqual(rebound, [])
class ARefusedCopyIsAnError(unittest.TestCase):
"""A PermissionError on a standalone copy was counted as "dir not found"
and the run ended on Done with exit code 0."""