From cd51f39d7b9804ef536e108ac3cb81a3e0bed24c Mon Sep 17 00:00:00 2001 From: ispyisail Date: Fri, 2 Oct 2026 10:05:24 +1300 Subject: [PATCH] qet-mcp: the scripts folder rule as a pure function, tested for Windows and macOS Checked against a real Windows package under Wine: QElectroTech keeps its data in %APPDATA%\QElectroTech\QElectroTech, next to which the scripts folder goes. Co-Authored-By: Claude Opus 5.5 --- misc/qet-mcp/qet_mcp.py | 30 ++++++++++++++++++++---------- misc/qet-mcp/test_qet_mcp.py | 22 ++++++++++++++++------ 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/misc/qet-mcp/qet_mcp.py b/misc/qet-mcp/qet_mcp.py index 72222da06..0e994560a 100755 --- a/misc/qet-mcp/qet_mcp.py +++ b/misc/qet-mcp/qet_mcp.py @@ -64,7 +64,7 @@ import subprocess import sys import tempfile import xml.etree.ElementTree as ET -from pathlib import Path, PurePath +from pathlib import Path, PurePath, PurePosixPath, PureWindowsPath SERVER_NAME = "qet-mcp" SERVER_VERSION = "0.1.0" @@ -2593,24 +2593,34 @@ SCRIPT_HEADER_HELP = ( "qet.showMessage() opens a dialog the user has to close.") +def default_scripts_dir(os_name: str, platform: str, env, home) -> PurePath: + """QETApp::dataDir() + "/scripts" for a given platform. + + dataDir() is Qt's AppDataLocation with organisation and application + both "QElectroTech" (main.cpp). Pure, so the Windows and macOS answers + are tested on any machine. + """ + if os_name == "nt": + appdata = env.get("APPDATA") + base = (PureWindowsPath(appdata) if appdata + else PureWindowsPath(home, "AppData", "Roaming")) + elif platform == "darwin": + base = PurePosixPath(home, "Library", "Application Support") + else: + base = PurePosixPath(env.get("XDG_DATA_HOME") or PurePosixPath(home, ".local", "share")) + return base / "QElectroTech" / "QElectroTech" / "scripts" + + def scripts_dir() -> Path: """The folder QElectroTech reads stored scripts from. - QETApp::dataDir() + "/scripts", where dataDir() is Qt's - AppDataLocation for organisation and application "QElectroTech". QET_MCP_SCRIPTS_DIR overrides it, for a QElectroTech started with --data-dir or a test. """ env = os.environ.get("QET_MCP_SCRIPTS_DIR", "").strip() if env: return Path(env).expanduser() - if os.name == "nt": - base = Path(os.environ.get("APPDATA") or Path.home() / "AppData" / "Roaming") - elif sys.platform == "darwin": - base = Path.home() / "Library" / "Application Support" - else: - base = Path(os.environ.get("XDG_DATA_HOME") or Path.home() / ".local" / "share") - return base / "QElectroTech" / "QElectroTech" / "scripts" + return Path(str(default_scripts_dir(os.name, sys.platform, os.environ, str(Path.home())))) def parse_script_header(text: str, script_id: str) -> dict: diff --git a/misc/qet-mcp/test_qet_mcp.py b/misc/qet-mcp/test_qet_mcp.py index d65e76626..ebbe49362 100644 --- a/misc/qet-mcp/test_qet_mcp.py +++ b/misc/qet-mcp/test_qet_mcp.py @@ -2917,12 +2917,22 @@ class ScriptStore(unittest.TestCase): "error": "no // ==QETScript== header"}]) def test_default_folder_is_qets_data_dir(self): - with mock.patch.dict(os.environ, {"QET_MCP_SCRIPTS_DIR": "", - "XDG_DATA_HOME": "/x/share"}), \ - mock.patch.object(m.os, "name", "posix"), \ - mock.patch.object(m.sys, "platform", "linux"): - self.assertEqual(m.scripts_dir(), - Path("/x/share/QElectroTech/QElectroTech/scripts")) + """QStandardPaths::AppDataLocation plus the organisation and + application names main.cpp sets, on each platform.""" + from pathlib import PurePosixPath, PureWindowsPath + f = m.default_scripts_dir + self.assertEqual(f("posix", "linux", {"XDG_DATA_HOME": "/x/share"}, "/home/u"), + PurePosixPath("/x/share/QElectroTech/QElectroTech/scripts")) + self.assertEqual(f("posix", "linux", {}, "/home/u"), + PurePosixPath("/home/u/.local/share/QElectroTech/QElectroTech/scripts")) + self.assertEqual(f("nt", "win32", {"APPDATA": r"C:\Users\u\AppData\Roaming"}, r"C:\Users\u"), + PureWindowsPath(r"C:\Users\u\AppData\Roaming\QElectroTech\QElectroTech\scripts")) + self.assertEqual(f("nt", "win32", {}, r"C:\Users\u"), + PureWindowsPath(r"C:\Users\u\AppData\Roaming\QElectroTech\QElectroTech\scripts")) + self.assertEqual(f("posix", "darwin", {}, "/Users/u"), + PurePosixPath("/Users/u/Library/Application Support/QElectroTech/QElectroTech/scripts")) + with mock.patch.dict(os.environ, {"QET_MCP_SCRIPTS_DIR": "/elsewhere"}): + self.assertEqual(m.scripts_dir(), Path("/elsewhere")) def test_install_does_not_need_a_binary_without_a_test(self): """Only a test run launches QElectroTech; storing a file must not be