Skip to content

Commit 40b7e3d

Browse files
authored
Merge pull request #431 from Integration-Automation/chore/static-analysis-backlog
Clear SonarCloud + Codacy static-analysis backlog
2 parents 1e0eef8 + fcb5910 commit 40b7e3d

36 files changed

Lines changed: 257 additions & 219 deletions

je_auto_control/gui/flow_editor/__init__.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@
1717
FlowEdge, FlowLayout, FlowNodePosition, layout_steps,
1818
)
1919

20+
_SCENE_MODULE = "je_auto_control.gui.flow_editor.scene"
21+
_TAB_MODULE = "je_auto_control.gui.flow_editor.tab"
2022
_LAZY_SUBMODULES = {
21-
"FlowEdgeItem": "je_auto_control.gui.flow_editor.scene",
22-
"FlowGraphScene": "je_auto_control.gui.flow_editor.scene",
23-
"FlowNodeItem": "je_auto_control.gui.flow_editor.scene",
24-
"FlowEditorTab": "je_auto_control.gui.flow_editor.tab",
23+
"FlowEdgeItem": _SCENE_MODULE,
24+
"FlowGraphScene": _SCENE_MODULE,
25+
"FlowNodeItem": _SCENE_MODULE,
26+
"FlowEditorTab": _TAB_MODULE,
2527
}
2628

2729

je_auto_control/gui/script_builder/command_schema.py

Lines changed: 114 additions & 104 deletions
Large diffs are not rendered by default.

je_auto_control/utils/accessibility/backends/base.py

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -29,76 +29,76 @@ def get_value(self, name: Optional[str] = None, role: Optional[str] = None,
2929
app_name: Optional[str] = None,
3030
automation_id: Optional[str] = None) -> Optional[str]:
3131
"""Return the matched control's value text, or None if not found."""
32-
self._unsupported("get_value")
32+
self._unsupported("get_value", name, role, app_name, automation_id)
3333

3434
def set_value(self, value: str, name: Optional[str] = None,
3535
role: Optional[str] = None, app_name: Optional[str] = None,
3636
automation_id: Optional[str] = None) -> bool:
3737
"""Set the matched control's value; return True on success."""
38-
self._unsupported("set_value")
38+
self._unsupported("set_value", value, name, role, app_name, automation_id)
3939

4040
def invoke(self, name: Optional[str] = None, role: Optional[str] = None,
4141
app_name: Optional[str] = None,
4242
automation_id: Optional[str] = None) -> bool:
4343
"""Invoke the matched control (e.g. press a button)."""
44-
self._unsupported("invoke")
44+
self._unsupported("invoke", name, role, app_name, automation_id)
4545

4646
def toggle(self, name: Optional[str] = None, role: Optional[str] = None,
4747
app_name: Optional[str] = None,
4848
automation_id: Optional[str] = None) -> bool:
4949
"""Toggle the matched control (e.g. a checkbox)."""
50-
self._unsupported("toggle")
50+
self._unsupported("toggle", name, role, app_name, automation_id)
5151

5252
def read_table(self, name: Optional[str] = None, role: Optional[str] = None,
5353
app_name: Optional[str] = None,
5454
automation_id: Optional[str] = None,
5555
) -> List[List[str]]:
5656
"""Read a grid/table/list control as rows of cell strings."""
57-
self._unsupported("read_table")
57+
self._unsupported("read_table", name, role, app_name, automation_id)
5858

5959
# --- extended control patterns (Expand / Selection / Range / Scroll) ----
6060

6161
def expand(self, name: Optional[str] = None, role: Optional[str] = None,
6262
app_name: Optional[str] = None,
6363
automation_id: Optional[str] = None) -> bool:
6464
"""Expand the matched control (ExpandCollapsePattern); True on success."""
65-
self._unsupported("expand")
65+
self._unsupported("expand", name, role, app_name, automation_id)
6666

6767
def collapse(self, name: Optional[str] = None, role: Optional[str] = None,
6868
app_name: Optional[str] = None,
6969
automation_id: Optional[str] = None) -> bool:
7070
"""Collapse the matched control (ExpandCollapsePattern); True on success."""
71-
self._unsupported("collapse")
71+
self._unsupported("collapse", name, role, app_name, automation_id)
7272

7373
def expand_state(self, name: Optional[str] = None, role: Optional[str] = None,
7474
app_name: Optional[str] = None,
7575
automation_id: Optional[str] = None) -> Optional[str]:
7676
"""Return ``expanded`` / ``collapsed`` / ``partial`` / ``leaf``, or None."""
77-
self._unsupported("expand_state")
77+
self._unsupported("expand_state", name, role, app_name, automation_id)
7878

7979
def select_item(self, name: Optional[str] = None, role: Optional[str] = None,
8080
app_name: Optional[str] = None,
8181
automation_id: Optional[str] = None) -> bool:
8282
"""Select the matched item (SelectionItemPattern); True on success."""
83-
self._unsupported("select_item")
83+
self._unsupported("select_item", name, role, app_name, automation_id)
8484

8585
def get_range(self, name: Optional[str] = None, role: Optional[str] = None,
8686
app_name: Optional[str] = None,
8787
automation_id: Optional[str] = None) -> Optional[Dict[str, Any]]:
8888
"""Return ``{value, minimum, maximum}`` (RangeValuePattern), or None."""
89-
self._unsupported("get_range")
89+
self._unsupported("get_range", name, role, app_name, automation_id)
9090

9191
def set_range_value(self, value: float, name: Optional[str] = None,
9292
role: Optional[str] = None, app_name: Optional[str] = None,
9393
automation_id: Optional[str] = None) -> bool:
9494
"""Set a slider / progress value (RangeValuePattern); True on success."""
95-
self._unsupported("set_range_value")
95+
self._unsupported("set_range_value", value, name, role, app_name, automation_id)
9696

9797
def scroll_into_view(self, name: Optional[str] = None,
9898
role: Optional[str] = None, app_name: Optional[str] = None,
9999
automation_id: Optional[str] = None) -> bool:
100100
"""Scroll the matched control into view (ScrollItemPattern); True on success."""
101-
self._unsupported("scroll_into_view")
101+
self._unsupported("scroll_into_view", name, role, app_name, automation_id)
102102

103103
# --- text patterns (TextPattern reads) ---------------------------------
104104

@@ -109,49 +109,49 @@ def document_text(self, name: Optional[str] = None, role: Optional[str] = None,
109109
110110
Reads multiline / document controls where ValuePattern returns ``""``.
111111
"""
112-
self._unsupported("document_text")
112+
self._unsupported("document_text", name, role, app_name, automation_id)
113113

114114
def selected_text(self, name: Optional[str] = None, role: Optional[str] = None,
115115
app_name: Optional[str] = None,
116116
automation_id: Optional[str] = None) -> Optional[str]:
117117
"""Return the control's currently selected text (TextPattern), or None."""
118-
self._unsupported("selected_text")
118+
self._unsupported("selected_text", name, role, app_name, automation_id)
119119

120120
def visible_text(self, name: Optional[str] = None, role: Optional[str] = None,
121121
app_name: Optional[str] = None,
122122
automation_id: Optional[str] = None) -> Optional[str]:
123123
"""Return only the on-screen text of the control (TextPattern), or None."""
124-
self._unsupported("visible_text")
124+
self._unsupported("visible_text", name, role, app_name, automation_id)
125125

126126
def find_text(self, text: str = "", ignore_case: bool = True,
127127
name: Optional[str] = None, role: Optional[str] = None,
128128
app_name: Optional[str] = None,
129129
automation_id: Optional[str] = None) -> bool:
130130
"""Return whether ``text`` occurs in the control (TextPattern.FindText)."""
131-
self._unsupported("find_text")
131+
self._unsupported("find_text", text, ignore_case, name, role, app_name, automation_id)
132132

133133
def select_text(self, text: str = "", ignore_case: bool = True,
134134
name: Optional[str] = None, role: Optional[str] = None,
135135
app_name: Optional[str] = None,
136136
automation_id: Optional[str] = None) -> bool:
137137
"""Find ``text`` and select its range (TextPattern.FindText + Select)."""
138-
self._unsupported("select_text")
138+
self._unsupported("select_text", text, ignore_case, name, role, app_name, automation_id)
139139

140140
def text_attributes(self, name: Optional[str] = None,
141141
role: Optional[str] = None, app_name: Optional[str] = None,
142142
automation_id: Optional[str] = None,
143143
) -> Optional[Dict[str, Any]]:
144144
"""Return formatting of the control's selection — ``{font_name, font_size,
145145
bold, italic, foreground_color}`` (TextPattern attributes), or None."""
146-
self._unsupported("text_attributes")
146+
self._unsupported("text_attributes", name, role, app_name, automation_id)
147147

148148
# --- keyboard focus ----------------------------------------------------
149149

150150
def set_focus(self, name: Optional[str] = None, role: Optional[str] = None,
151151
app_name: Optional[str] = None,
152152
automation_id: Optional[str] = None) -> bool:
153153
"""Set keyboard focus on the matched control (SetFocus); True on success."""
154-
self._unsupported("set_focus")
154+
self._unsupported("set_focus", name, role, app_name, automation_id)
155155

156156
# --- virtualized items (realize off-screen list / grid items) -----------
157157

@@ -168,7 +168,7 @@ def find_virtual_item(self, item_name: Optional[str] = None, by: str = "name",
168168
(``VirtualizedItemPattern``) so it exists as a real element. Returns the
169169
realized element, or None if the container or item isn't found.
170170
"""
171-
self._unsupported("find_virtual_item")
171+
self._unsupported("find_virtual_item", item_name, by, container_name, container_role, app_name, automation_id)
172172

173173
# --- rich element properties -------------------------------------------
174174

@@ -182,7 +182,7 @@ def get_properties(self, name: Optional[str] = None,
182182
``enabled`` / ``offscreen`` / ``help_text`` / ``item_status`` /
183183
``accelerator_key`` / ``access_key`` / ``orientation``.
184184
"""
185-
self._unsupported("get_properties")
185+
self._unsupported("get_properties", name, role, app_name, automation_id)
186186

187187
# --- table headers + cell addressing (TablePattern / GridItemPattern) ---
188188

@@ -192,7 +192,7 @@ def get_table_headers(self, name: Optional[str] = None,
192192
automation_id: Optional[str] = None,
193193
) -> Optional[Dict[str, Any]]:
194194
"""Return a table's header labels as ``{columns: [...], rows: [...]}``."""
195-
self._unsupported("get_table_headers")
195+
self._unsupported("get_table_headers", name, role, app_name, automation_id)
196196

197197
def get_grid_cell(self, row: int = 0, column: int = 0,
198198
name: Optional[str] = None, role: Optional[str] = None,
@@ -201,7 +201,7 @@ def get_grid_cell(self, row: int = 0, column: int = 0,
201201
) -> Optional[Dict[str, Any]]:
202202
"""Return the cell at ``(row, column)`` as ``{value, row, column,
203203
row_span, column_span}`` (GridPattern.GetItem + GridItemPattern)."""
204-
self._unsupported("get_grid_cell")
204+
self._unsupported("get_grid_cell", row, column, name, role, app_name, automation_id)
205205

206206
# --- transform + window patterns (UIA-element-level) --------------------
207207

@@ -210,21 +210,21 @@ def move_element(self, x: float = 0.0, y: float = 0.0,
210210
app_name: Optional[str] = None,
211211
automation_id: Optional[str] = None) -> bool:
212212
"""Move the matched element to ``(x, y)`` (TransformPattern); True on success."""
213-
self._unsupported("move_element")
213+
self._unsupported("move_element", x, y, name, role, app_name, automation_id)
214214

215215
def resize_element(self, width: float = 0.0, height: float = 0.0,
216216
name: Optional[str] = None, role: Optional[str] = None,
217217
app_name: Optional[str] = None,
218218
automation_id: Optional[str] = None) -> bool:
219219
"""Resize the matched element (TransformPattern); True on success."""
220-
self._unsupported("resize_element")
220+
self._unsupported("resize_element", width, height, name, role, app_name, automation_id)
221221

222222
def set_window_state(self, state: str = "normal",
223223
name: Optional[str] = None, role: Optional[str] = None,
224224
app_name: Optional[str] = None,
225225
automation_id: Optional[str] = None) -> bool:
226226
"""Set a window's visual state ``normal`` / ``maximized`` / ``minimized``."""
227-
self._unsupported("set_window_state")
227+
self._unsupported("set_window_state", state, name, role, app_name, automation_id)
228228

229229
def window_interaction_state(self, name: Optional[str] = None,
230230
role: Optional[str] = None,
@@ -233,7 +233,7 @@ def window_interaction_state(self, name: Optional[str] = None,
233233
) -> Optional[str]:
234234
"""Return a window's interaction state — ``ready`` / ``blocked_by_modal`` /
235235
``not_responding`` / ``running`` / ``closing`` (WindowPattern), or None."""
236-
self._unsupported("window_interaction_state")
236+
self._unsupported("window_interaction_state", name, role, app_name, automation_id)
237237

238238
# --- MSAA bridge (LegacyIAccessiblePattern) ----------------------------
239239

@@ -247,15 +247,15 @@ def legacy_info(self, name: Optional[str] = None, role: Optional[str] = None,
247247
last-resort read for legacy Win32 controls that expose nothing useful via
248248
the modern UIA patterns.
249249
"""
250-
self._unsupported("legacy_info")
250+
self._unsupported("legacy_info", name, role, app_name, automation_id)
251251

252252
def legacy_default_action(self, name: Optional[str] = None,
253253
role: Optional[str] = None,
254254
app_name: Optional[str] = None,
255255
automation_id: Optional[str] = None) -> bool:
256256
"""Fire an old control's MSAA default action (DoDefaultAction); True on
257257
success — the fallback when Value / Invoke / Toggle all do nothing."""
258-
self._unsupported("legacy_default_action")
258+
self._unsupported("legacy_default_action", name, role, app_name, automation_id)
259259

260260
# --- container selection + views (Selection / MultipleView patterns) ----
261261

@@ -265,21 +265,21 @@ def get_selection(self, name: Optional[str] = None, role: Optional[str] = None,
265265
) -> Optional[Dict[str, Any]]:
266266
"""Return a container's selection state — ``{items, can_select_multiple,
267267
is_required}`` (SelectionPattern), or None."""
268-
self._unsupported("get_selection")
268+
self._unsupported("get_selection", name, role, app_name, automation_id)
269269

270270
def list_views(self, name: Optional[str] = None, role: Optional[str] = None,
271271
app_name: Optional[str] = None,
272272
automation_id: Optional[str] = None,
273273
) -> Optional[Dict[str, Any]]:
274274
"""Return a control's selectable views — ``{current, views: [...]}``
275275
(MultipleViewPattern: list / details / tile / …), or None."""
276-
self._unsupported("list_views")
276+
self._unsupported("list_views", name, role, app_name, automation_id)
277277

278278
def set_view(self, view: str = "", name: Optional[str] = None,
279279
role: Optional[str] = None, app_name: Optional[str] = None,
280280
automation_id: Optional[str] = None) -> bool:
281281
"""Switch a control to the named view (MultipleViewPattern); True on success."""
282-
self._unsupported("set_view")
282+
self._unsupported("set_view", view, name, role, app_name, automation_id)
283283

284284
# --- reactive events (UIA event subscription) --------------------------
285285

@@ -291,9 +291,9 @@ def wait_for_focus_change(self, timeout: float = 5.0,
291291
A zero-latency native wait (UIA AddFocusChangedEventHandler) — unlike the
292292
polling recorder, it can't miss a fast focus transition.
293293
"""
294-
self._unsupported("wait_for_focus_change")
294+
self._unsupported("wait_for_focus_change", timeout)
295295

296-
def _unsupported(self, operation: str):
296+
def _unsupported(self, operation: str, *context: Any):
297297
"""Raise a clear error for an action this backend can't perform."""
298298
raise AccessibilityNotAvailableError(
299299
f"{operation} is not supported by the {self.name} backend",

je_auto_control/utils/assertion/assertions.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,11 +489,12 @@ def assert_by_description(description: str,
489489
)
490490
passed = (matched == present)
491491
state = "shows" if present else "does not show"
492+
verdict = "match" if matched else "no match"
492493
message = (
493494
f"assert_by_description passed: screen {state} {description!r}"
494495
if passed else
495496
f"assert_by_description failed: expected screen to {state} "
496-
f"{description!r} (VLM verdict: {'match' if matched else 'no match'})"
497+
f"{description!r} (VLM verdict: {verdict})"
497498
)
498499
return _finalize(
499500
"vlm", passed, message,

je_auto_control/utils/color_match/color_match.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@
2626

2727
def _hsv(source, region, is_haystack: bool):
2828
import cv2
29-
rgb = (_to_rgb(source) if source is not None
30-
else _grab_rgb(region)) if is_haystack else _to_rgb(source)
29+
if is_haystack:
30+
rgb = _to_rgb(source) if source is not None else _grab_rgb(region)
31+
else:
32+
rgb = _to_rgb(source)
3133
return cv2.cvtColor(rgb, cv2.COLOR_RGB2HSV)
3234

3335

je_auto_control/utils/config_bundle/__main__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ def _do_export(output: Path, root: Optional[Path]) -> int:
6464

6565
def _do_import(source: Path, root: Optional[Path], dry_run: bool) -> int:
6666
try:
67-
bundle = json.loads(source.read_text(encoding="utf-8"))
67+
# source is an operator-supplied CLI path, not remote input
68+
bundle = json.loads(source.read_text(encoding="utf-8")) # NOSONAR
6869
except (OSError, ValueError) as error:
6970
print(f"failed to read {source}: {error}", file=sys.stderr)
7071
return 2

je_auto_control/utils/element_scoring/element_scoring.py

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,26 @@ def _proximity(element: Element, anchor: Sequence[int]) -> float:
4040
return 1.0 / (1.0 + distance / 100.0)
4141

4242

43+
def _signal_parts(element: Element, want_role: Optional[str],
44+
want_name: Optional[str],
45+
similarity: Callable[[str, str], float],
46+
prefer_enabled: bool,
47+
anchor: Optional[Sequence[int]]) -> Dict[str, float]:
48+
"""Build the per-signal 0..1 breakdown for one ``element``."""
49+
parts: Dict[str, float] = {}
50+
if want_role is not None:
51+
parts["role"] = (1.0 if str(element.get("role", "")).lower()
52+
== str(want_role).lower() else 0.0)
53+
if want_name is not None:
54+
parts["name"] = float(similarity(want_name,
55+
str(element.get("name", ""))))
56+
if anchor is not None:
57+
parts["proximity"] = _proximity(element, anchor)
58+
if prefer_enabled:
59+
parts["enabled"] = 1.0 if element.get("enabled", True) else 0.0
60+
return parts
61+
62+
4363
def score_candidates(candidates: Sequence[Element], *,
4464
want_role: Optional[str] = None,
4565
want_name: Optional[str] = None,
@@ -57,17 +77,8 @@ def score_candidates(candidates: Sequence[Element], *,
5777
similarity = name_similarity or fuzzy_ratio
5878
scored: List[ScoredCandidate] = []
5979
for element in candidates:
60-
parts: Dict[str, float] = {}
61-
if want_role is not None:
62-
parts["role"] = (1.0 if str(element.get("role", "")).lower()
63-
== str(want_role).lower() else 0.0)
64-
if want_name is not None:
65-
parts["name"] = float(similarity(want_name,
66-
str(element.get("name", ""))))
67-
if anchor is not None:
68-
parts["proximity"] = _proximity(element, anchor)
69-
if prefer_enabled:
70-
parts["enabled"] = 1.0 if element.get("enabled", True) else 0.0
80+
parts = _signal_parts(element, want_role, want_name, similarity,
81+
prefer_enabled, anchor)
7182
score = sum(parts.values()) / len(parts) if parts else 0.0
7283
scored.append(ScoredCandidate(element, round(score, 4), parts))
7384
scored.sort(key=lambda candidate: candidate.score, reverse=True)

0 commit comments

Comments
 (0)