Skip to content

Commit 326dba6

Browse files
committed
GHA CI: add checks for grid items order
Now all items under `QGridLayout` are required to be sorted. This allow us to omit tabstop order. The tabstop order will follow the layout order.
1 parent 4c6dd8e commit 326dba6

File tree

4 files changed

+105
-4
lines changed

4 files changed

+105
-4
lines changed

.github/workflows/ci_python.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434
- name: Lint code (auxiliary scripts)
3535
run: |
3636
pyflakes $PY_FILES
37-
bandit --skip B314,B405 $PY_FILES
37+
bandit --skip B101,B314,B405 $PY_FILES
3838
3939
- name: Format code (auxiliary scripts)
4040
run: |
@@ -61,7 +61,7 @@ jobs:
6161
echo $PY_FILES
6262
echo "PY_FILES=$PY_FILES" >> "$GITHUB_ENV"
6363
64-
- name: Check typings (search engine)
64+
- name: Check typings (search engine)
6565
run: |
6666
MYPYPATH="src/searchengine/nova3" \
6767
mypy \
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
#!/usr/bin/env python3
2+
3+
# A pre-commit hook for checking items order in grid layouts
4+
# Copyright (C) 2024 Mike Tzou (Chocobo1)
5+
#
6+
# This program is free software; you can redistribute it and/or
7+
# modify it under the terms of the GNU General Public License
8+
# as published by the Free Software Foundation; either version 2
9+
# of the License, or (at your option) any later version.
10+
#
11+
# This program is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
# GNU General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU General Public License
17+
# along with this program; if not, write to the Free Software
18+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19+
#
20+
# In addition, as a special exception, the copyright holders give permission to
21+
# link this program with the OpenSSL project's "OpenSSL" library (or with
22+
# modified versions of it that use the same license as the "OpenSSL" library),
23+
# and distribute the linked executables. You must obey the GNU General Public
24+
# License in all respects for all of the code used other than "OpenSSL". If you
25+
# modify file(s), you may extend this exception to your version of the file(s),
26+
# but you are not obligated to do so. If you do not wish to do so, delete this
27+
# exception statement from your version.
28+
29+
from collections.abc import Callable, Sequence
30+
from typing import Optional
31+
import argparse
32+
import re
33+
import xml.etree.ElementTree as ElementTree
34+
import sys
35+
36+
37+
def traversePostOrder(root: ElementTree.Element, visitFunc: Callable[[ElementTree.Element], None]) -> None:
38+
stack = [(root, False)]
39+
40+
while len(stack) > 0:
41+
(element, visit) = stack.pop()
42+
if visit:
43+
visitFunc(element)
44+
else:
45+
stack.append((element, True))
46+
stack.extend((child, False) for child in reversed(element))
47+
48+
49+
def modifyElement(element: ElementTree.Element) -> None:
50+
def getSortKey(e: ElementTree.Element) -> tuple[int, int]:
51+
if e.tag == 'item':
52+
return (int(e.attrib['row']), int(e.attrib['column']))
53+
return (-1, -1) # don't care
54+
55+
if element.tag == 'layout' and element.attrib['class'] == 'QGridLayout' and len(element) > 0:
56+
element[:] = sorted(element, key=getSortKey)
57+
58+
# workaround_2a: ElementTree will unescape `"` and we need to escape it back
59+
if element.tag == 'string' and element.text is not None:
60+
element.text = element.text.replace('"', '"')
61+
62+
63+
def main(argv: Optional[Sequence[str]] = None) -> int:
64+
parser = argparse.ArgumentParser()
65+
parser.add_argument('filenames', nargs='*', help='Filenames to check')
66+
args = parser.parse_args(argv)
67+
68+
for filename in args.filenames:
69+
with open(filename, 'r+') as f:
70+
orig = f.read()
71+
root = ElementTree.fromstring(orig)
72+
traversePostOrder(root, modifyElement)
73+
ElementTree.indent(root, ' ')
74+
75+
# workaround_1: cannot use `xml_declaration=True` since it uses single quotes instead of Qt preferred double quotes
76+
ret = f'<?xml version="1.0" encoding="UTF-8"?>\n{ElementTree.tostring(root, 'unicode')}\n'
77+
78+
# workaround_2b: ElementTree will turn `&quot;` into `&amp;quot;`, so revert it back
79+
ret = ret.replace('&amp;quot;', '&quot;')
80+
81+
# workaround_3: Qt prefers no whitespaces in self-closing tags
82+
ret = re.sub('<(.+) +/>', r'<\1/>', ret)
83+
84+
if ret != orig:
85+
f.seek(0)
86+
f.write(ret)
87+
f.truncate()
88+
89+
return 0
90+
91+
92+
if __name__ == '__main__':
93+
sys.exit(main())

.github/workflows/helper/pre-commit/check_translation_tag.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@
2626
# but you are not obligated to do so. If you do not wish to do so, delete this
2727
# exception statement from your version.
2828

29-
from typing import Optional, Sequence
29+
from collections.abc import Sequence
30+
from typing import Optional
3031
import argparse
3132
import re
33+
import sys
3234

3335

3436
def main(argv: Optional[Sequence[str]] = None) -> int:
@@ -67,4 +69,4 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
6769

6870

6971
if __name__ == '__main__':
70-
exit(main())
72+
sys.exit(main())

.pre-commit-config.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
repos:
22
- repo: local
33
hooks:
4+
- id: check-grid-order
5+
name: Check items order in grid layouts
6+
entry: .github/workflows/helper/pre-commit/check_grid_items_order.py
7+
language: script
8+
files: \.ui$
9+
410
- id: check-translation-tag
511
name: Check newline characters in <translation> tag
612
entry: .github/workflows/helper/pre-commit/check_translation_tag.py

0 commit comments

Comments
 (0)