Skip to content

Commit 5ede3b1

Browse files
committed
Skip Win32 MCP tests on non-Windows; trim lazy __all__ to clear pylint E0603
1 parent 66d76a3 commit 5ede3b1

3 files changed

Lines changed: 34 additions & 17 deletions

File tree

je_auto_control/gui/flow_editor/__init__.py

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@
44
the same :class:`Step` model + JSON action schema, so a script
55
authored in one view loads cleanly in the other.
66
7-
Public surface::
8-
9-
from je_auto_control.gui.flow_editor import (
10-
FlowEditorTab, FlowGraphScene, layout_steps,
11-
)
12-
13-
The ``layout`` module is Qt-free and eager so headless tests can import
14-
it without instantiating PySide6. ``scene`` and ``tab`` are loaded
15-
lazily via :func:`__getattr__` because they pull in Qt.
7+
The ``layout`` module is Qt-free and eager so headless tests can
8+
import it without instantiating PySide6. The Qt-dependent names
9+
(``FlowGraphScene``, ``FlowEditorTab`` …) load lazily via
10+
:func:`__getattr__`; they are intentionally absent from ``__all__``
11+
because Pylint's E0603 refuses to certify names that ``import *`` can
12+
not resolve at module-load time. ``from je_auto_control.gui.flow_editor
13+
import FlowEditorTab`` still works — Python falls through to
14+
``__getattr__`` when the attribute is not pre-bound.
1615
"""
1716
from je_auto_control.gui.flow_editor.layout import (
1817
FlowEdge, FlowLayout, FlowNodePosition, layout_steps,
@@ -27,14 +26,16 @@
2726

2827

2928
def __getattr__(name):
30-
if name in _LAZY_SUBMODULES:
31-
import importlib
32-
module = importlib.import_module(_LAZY_SUBMODULES[name])
33-
return getattr(module, name)
34-
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
29+
target = _LAZY_SUBMODULES.get(name)
30+
if target is None:
31+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
32+
import importlib
33+
# Argument is looked up from a hard-coded dict above, never user
34+
# input — safe to import dynamically.
35+
module = importlib.import_module(target) # nosemgrep
36+
return getattr(module, name)
3537

3638

3739
__all__ = [
38-
"FlowEdge", "FlowEditorTab", "FlowEdgeItem", "FlowGraphScene",
39-
"FlowLayout", "FlowNodeItem", "FlowNodePosition", "layout_steps",
40+
"FlowEdge", "FlowLayout", "FlowNodePosition", "layout_steps",
4041
]

je_auto_control/gui/script_builder/__init__.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
and can be imported directly from headless tests::
66
77
from je_auto_control.gui.script_builder.step_model import Step
8+
9+
``__all__`` is empty on purpose: Pylint's E0603 refuses to certify
10+
``ScriptBuilderTab`` because it is not bound at module-load time.
11+
Callers reach the tab via attribute access, which falls through to
12+
:func:`__getattr__` and loads the Qt submodule on demand.
813
"""
914

1015

@@ -18,4 +23,4 @@ def __getattr__(name):
1823
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
1924

2025

21-
__all__ = ["ScriptBuilderTab"]
26+
__all__: list[str] = []

test/unit_test/headless/test_mcp_server.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@
88
import json
99
import math
1010
import os
11+
import sys
1112
import threading
1213
from typing import Any, Dict, List
1314

15+
import pytest
16+
1417
from je_auto_control.utils.mcp_server.context import (
1518
OperationCancelledError, ToolCallContext,
1619
)
@@ -1343,6 +1346,10 @@ def test_window_geometry_tools_present_in_default_registry():
13431346
"ac_window_maximize", "ac_window_restore"}.issubset(names)
13441347

13451348

1349+
@pytest.mark.skipif(
1350+
sys.platform not in ("win32", "cygwin", "msys"),
1351+
reason="windows_window_manage uses ctypes.WINFUNCTYPE; Win32-only.",
1352+
)
13461353
def test_window_move_calls_into_windows_manager(monkeypatch):
13471354
import je_auto_control.utils.mcp_server.tools._handlers as handlers
13481355
import je_auto_control.wrapper.auto_control_window as window_module
@@ -1368,6 +1375,10 @@ def fake_move(hwnd, x, y, width, height, repaint=True):
13681375
"width": 800, "height": 600}
13691376

13701377

1378+
@pytest.mark.skipif(
1379+
sys.platform not in ("win32", "cygwin", "msys"),
1380+
reason="windows_window_manage uses ctypes.WINFUNCTYPE; Win32-only.",
1381+
)
13711382
def test_window_minimize_uses_show_command_six(monkeypatch):
13721383
"""ShowWindow flag 6 is SW_MINIMIZE."""
13731384
import je_auto_control.wrapper.auto_control_window as window_module

0 commit comments

Comments
 (0)