ver Jan10th
new Thunderbird task config
This commit is contained in:
@@ -6,4 +6,4 @@ from .docs import is_first_line_centered, check_file_exists, compare_contains_im
|
||||
from .pdf import check_pdf_pages
|
||||
from .libreoffice import check_libre_locale
|
||||
#from .vlc import is_vlc_playing
|
||||
from .general import check_csv
|
||||
from .general import check_csv, check_accessibility_tree
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
import csv
|
||||
|
||||
import lxml.etree
|
||||
from lxml.etree import _Element
|
||||
from lxml.cssselect import CSSSelector
|
||||
|
||||
from typing import Dict, List
|
||||
from typing import Callable, Any
|
||||
from numbers import Number
|
||||
|
||||
import operator
|
||||
from rapidfuzz import fuzz
|
||||
import functools
|
||||
|
||||
def _match_record(pattern: Dict[str, str], item: Dict[str, str]) -> float:
|
||||
return all(k in item and item[k]==val for k, val in pattern.items())
|
||||
@@ -28,3 +39,57 @@ def check_csv(result: str, rules: Dict[str, List[Dict[str, str]]]) -> float:
|
||||
expect_metrics[i] = expect_metrics[i] or _match_record(r, rcd)
|
||||
unexpect_metric = unexpect_metric and all(_match_record(r, rcd) for r in rules.get("unexpect", []))
|
||||
return float(all(expect_metrics) and unexpect_metric)
|
||||
|
||||
_accessibility_ns_map = { "st": "uri:deskat:state.at-spi.gnome.org"
|
||||
, "attr": "uri:deskat:attributes.at-spi.gnome.org"
|
||||
, "cp": "uri:deskat:component.at-spi.gnome.org"
|
||||
, "doc": "uri:deskat:document.at-spi.gnome.org"
|
||||
, "docattr": "uri:deskat:attributes.document.at-spi.gnome.org"
|
||||
, "txt": "uri:deskat:text.at-spi.gnome.org"
|
||||
, "val": "uri:deskat:value.at-spi.gnome.org"
|
||||
, "act": "uri:deskat:action.at-spi.gnome.org"
|
||||
}
|
||||
def check_accessibility_tree(result: str, rules: Dict[str, Any]) -> float:
|
||||
"""
|
||||
Args:
|
||||
result (str): XML of GNOME Accessibility Tree
|
||||
rules (Dict[str, Any]): dict like
|
||||
{
|
||||
"selectors": list of str as CSS selectors, will be connected by ", "
|
||||
to form a composite selector. Only one from `selectors` and
|
||||
`xpath` is needed. If both are present, `xpath` takes the
|
||||
priority.
|
||||
"xpath": str as xpath. Only one from `selectors` and `xpath` is
|
||||
needed. If both are present, `xpath` takes the priority.
|
||||
"text": str as the expected text content of the selected element.
|
||||
"exact": bool specifying whether exact match or fuzzy match should
|
||||
be performed. defaults to True
|
||||
}
|
||||
|
||||
Returns:
|
||||
float
|
||||
"""
|
||||
|
||||
at: _Element = lxml.etree.fromstring(result)
|
||||
if "xpath" in rules:
|
||||
elements: List[_Element] = at.xpath(rules["xpath"], namespaces=_accessibility_ns_map)
|
||||
elif "selectors" in rules:
|
||||
selector = CSSSelector(", ".join(rules["selectors"]), namespaces=_accessibility_ns_map)
|
||||
elements: List[_Element] = selector(at)
|
||||
else:
|
||||
raise ValueError("At least one of xpath and selectors is required")
|
||||
|
||||
if len(elements)==0:
|
||||
return 0.
|
||||
|
||||
if "text" in rules:
|
||||
match_func: Callable[[str], Number] = functools.partial( operator.eq if rules["exact"] else fuzz.ratio
|
||||
, rules["text"]
|
||||
)
|
||||
match_score: Number = 0
|
||||
for elm in elements:
|
||||
match_score = max(match_score, match_func(elm.text or None))
|
||||
else:
|
||||
match_score = 1.
|
||||
|
||||
return float(match_score)
|
||||
|
||||
Reference in New Issue
Block a user