Skip to content

Commit 4577969

Browse files
chore: improve typing and tests (#573)
1 parent db386ca commit 4577969

8 files changed

Lines changed: 122 additions & 37 deletions

File tree

.github/workflows/testing.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,10 @@ jobs:
5555
tools/check.import.sh
5656
5757
- name: Install dependencies
58+
shell: bash
5859
run: |
5960
python -m pip install --upgrade pip
60-
python -m pip install flake8 pytest
61-
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
61+
python -m pip install -e 'libs/pyTermTk[test]'
6262
6363
- name: Lint with flake8
6464
run: |

libs/pyTermTk/TermTk/TTkAbstract/abstractscrollview.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,8 @@ def viewMoveTo(self, x: int, y: int) -> None:
503503
return
504504
self._excludeEvent = True
505505
for widget in self.iterWidgets():
506-
widget.viewMoveTo(x,y)
506+
if isinstance(widget, TTkAbstractScrollViewInterface):
507+
widget.viewMoveTo(x,y)
507508
self._excludeEvent = False
508509
self._viewOffsetX = x
509510
self._viewOffsetY = y
@@ -595,9 +596,10 @@ def viewFullAreaSize(self) -> Tuple[int,int]:
595596
'''
596597
w,h=0,0
597598
for widget in self.iterWidgets():
598-
ww,wh = widget.viewFullAreaSize()
599-
w = max(w,ww)
600-
h = max(h,wh)
599+
if isinstance(widget, TTkAbstractScrollViewInterface):
600+
ww,wh = widget.viewFullAreaSize()
601+
w = max(w,ww)
602+
h = max(h,wh)
601603
return w,h
602604

603605
# Override this function
@@ -609,9 +611,10 @@ def viewDisplayedSize(self) -> Tuple[int,int]:
609611
'''
610612
w,h=0,0
611613
for widget in self.iterWidgets():
612-
ww,wh = widget.viewDisplayedSize()
613-
w = max(w,ww)
614-
h = max(h,wh)
614+
if isinstance(widget, TTkAbstractScrollViewInterface):
615+
ww,wh = widget.viewDisplayedSize()
616+
w = max(w,ww)
617+
h = max(h,wh)
615618
return w,h
616619

617620
def getViewOffsets(self) -> Tuple[int,int]:

libs/pyTermTk/TermTk/TTkCore/timer.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,12 @@
2323
__all__ = ['TTkTimer']
2424

2525
import importlib.util
26+
from typing import TYPE_CHECKING
27+
28+
from .timer_interface import _TTkTimer_Interface as TTkTimer
2629

2730
if importlib.util.find_spec('pyodideProxy'):
28-
from .timer_pyodide import TTkTimer
31+
from .timer_pyodide import _TTkTimer_Pyodide as TTkTimer
2932
else:
30-
from .timer_unix import TTkTimer
33+
from .timer_unix import _TTkTimer_Unix as TTkTimer
3134

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# MIT License
2+
#
3+
# Copyright (c) 2021 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com>
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy
6+
# of this software and associated documentation files (the "Software"), to deal
7+
# in the Software without restriction, including without limitation the rights
8+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
# copies of the Software, and to permit persons to whom the Software is
10+
# furnished to do so, subject to the following conditions:
11+
#
12+
# The above copyright notice and this permission notice shall be included in all
13+
# copies or substantial portions of the Software.
14+
#
15+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
# SOFTWARE.
22+
23+
__all__ = []
24+
25+
from typing import Callable,Optional,Protocol
26+
27+
from TermTk.TTkCore.signal import pyTTkSignal, pyTTkSlot
28+
29+
class _TTkTimer_Interface(Protocol):
30+
'''Protocol defining the interface for timer implementations.'''
31+
32+
timeout: pyTTkSignal
33+
34+
def __init__(
35+
self,
36+
name: Optional[str] = None,
37+
excepthook: Optional[Callable[[Exception], None]] = None) -> None:
38+
'''Initialize timer with optional name and exception handler.
39+
40+
:param name: Optional name for the timer
41+
:type name: str, optional
42+
:param excepthook: Optional callback for exception handling
43+
:type excepthook: Callable[[Exception], None], optional
44+
'''
45+
...
46+
47+
def quit(self) -> None:
48+
'''Stop the timer and cleanup resources.'''
49+
...
50+
51+
def run(self) -> None:
52+
'''Main timer loop (typically runs in a thread).'''
53+
...
54+
55+
def start(self, sec: float = 0.0) -> None:
56+
'''Start the timer with specified interval.
57+
58+
:param sec: Interval in seconds
59+
:type sec: float
60+
'''
61+
...
62+
63+
def stop(self) -> None:
64+
'''Stop the timer without cleanup.'''
65+
...

libs/pyTermTk/TermTk/TTkCore/timer_pyodide.py

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,18 @@
2222

2323
from __future__ import annotations
2424

25-
__all__ = ['TTkTimer']
25+
__all__ = []
2626

2727
from typing import Optional,Callable,Dict
2828

2929
from TermTk.TTkCore.helper import TTkHelper
3030
from TermTk.TTkCore.signal import pyTTkSlot, pyTTkSignal
31+
from TermTk.TTkCore.timer_interface import _TTkTimer_Interface
3132

32-
import pyodideProxy
33+
import pyodideProxy # type: ignore[import-not-found]
3334

34-
class TTkTimer():
35-
_timers:Dict[int,TTkTimer] = {}
35+
class _TTkTimer_Pyodide(_TTkTimer_Interface):
36+
_timers:Dict[int,_TTkTimer_Pyodide] = {}
3637
_uid = 0
3738

3839
__slots__ = (
@@ -50,38 +51,38 @@ def __init__(
5051
self._running = True
5152
self._timer = None
5253

53-
self._id = TTkTimer._uid
54-
TTkTimer._uid +=1
55-
TTkTimer._timers[self._id] = self
54+
self._id = _TTkTimer_Pyodide._uid
55+
_TTkTimer_Pyodide._uid +=1
56+
_TTkTimer_Pyodide._timers[self._id] = self
5657

5758
@staticmethod
58-
def triggerTimerId(tid):
59-
if tid in TTkTimer._timers:
59+
def triggerTimerId(tid) -> None:
60+
if tid in _TTkTimer_Pyodide._timers:
6061
# Little hack to avoid deadloop in pyodide
6162
if rw := TTkHelper._rootWidget:
6263
rw._paintEvent.set()
63-
TTkTimer._timers[tid].timeout.emit()
64+
_TTkTimer_Pyodide._timers[tid].timeout.emit()
6465

6566
@staticmethod
66-
def pyodideQuit():
67-
for timer in TTkTimer._timers:
68-
TTkTimer._timers[timer].timeout.clearAll()
69-
TTkTimer._timers[timer]._running = False
70-
TTkTimer._timers[timer].quit()
71-
TTkTimer._timers = {}
67+
def pyodideQuit() -> None:
68+
for timer in _TTkTimer_Pyodide._timers:
69+
_TTkTimer_Pyodide._timers[timer].timeout.clearAll()
70+
_TTkTimer_Pyodide._timers[timer]._running = False
71+
_TTkTimer_Pyodide._timers[timer].quit()
72+
_TTkTimer_Pyodide._timers = {}
7273

73-
def quit(self):
74+
def quit(self) -> None:
7475
pass
7576

7677
@pyTTkSlot(float)
77-
def start(self, sec=0.0):
78+
def start(self, sec=0.0) -> None:
7879
self.stop()
7980
if self._running:
8081
self._timer = pyodideProxy.setTimeout(int(sec*1000), self._id)
8182
# pyodideProxy.consoleLog(f"Timer {self._timer}")
8283

8384
@pyTTkSlot()
84-
def stop(self):
85+
def stop(self) -> None:
8586
# pyodideProxy.consoleLog(f"Timer {self._timer}")
8687
if self._timer:
8788
pyodideProxy.stopTimeout(self._timer)

libs/pyTermTk/TermTk/TTkCore/timer_unix.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,17 @@
2020
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2121
# SOFTWARE.
2222

23-
__all__ = ['TTkTimer']
23+
__all__ = []
2424

2525
from typing import Optional,Callable
2626

2727
import threading
2828

2929
from TermTk.TTkCore.signal import pyTTkSlot, pyTTkSignal
3030
from TermTk.TTkCore.helper import TTkHelper
31+
from TermTk.TTkCore.timer_interface import _TTkTimer_Interface
3132

32-
class TTkTimer(threading.Thread):
33+
class _TTkTimer_Unix(threading.Thread, _TTkTimer_Interface):
3334
__slots__ = (
3435
'timeout', '_delay',
3536
'_timer', '_quit', '_start',
@@ -51,14 +52,14 @@ def __init__(
5152
super().__init__(name=name)
5253
TTkHelper.quitEvent.connect(self.quit)
5354

54-
def quit(self):
55+
def quit(self) -> None:
5556
TTkHelper.quitEvent.disconnect(self.quit)
5657
self.timeout.clear()
5758
self._quit.set()
5859
self._timer.set()
5960
self._start.set()
6061

61-
def run(self):
62+
def run(self) -> None:
6263
try:
6364
while not self._quit.is_set():
6465
self._start.wait()
@@ -73,7 +74,7 @@ def run(self):
7374
raise e
7475

7576
@pyTTkSlot(float)
76-
def start(self, sec:float=0.0):
77+
def start(self, sec:float=0.0) -> None:
7778
self._delay = sec
7879
self._timer.set()
7980
self._timer.clear()
@@ -82,5 +83,5 @@ def start(self, sec:float=0.0):
8283
super().start()
8384

8485
@pyTTkSlot()
85-
def stop(self):
86+
def stop(self) -> None:
8687
self._timer.set()

libs/pyTermTk/TermTk/TTkTestWidgets/tominspector.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,12 @@ def __init__(self, *args, **kwargs) -> None:
151151
self.setLayout(layout)
152152

153153
self._domTree = TTkTree()
154-
self._domTree.setHeaderLabels(["Object", "Class", "Visibility", "Layout"])
154+
self._domTree.setHeaderLabels([
155+
TTkString("Object"),
156+
TTkString("Class"),
157+
TTkString("Visibility"),
158+
TTkString("Layout")
159+
])
155160
if TTkHelper._rootWidget:
156161
self._domTree.addTopLevelItem(TTkTomInspector._getTomTreeItem(TTkHelper._rootWidget._widgetItem))
157162

libs/pyTermTk/pyproject.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@
3939
[tool.setuptools.packages.find]
4040
where = ["."]
4141

42+
[project.optional-dependencies]
43+
test = [
44+
"pytest>=8.3.4",
45+
"flake8>=7.2.0",
46+
"mypy>=1.15.0"
47+
]
48+
4249
[tool.setuptools.dynamic]
4350
version = {attr = "TermTk.__version__"}
4451

0 commit comments

Comments
 (0)