Browse Source

chore: improve typing and tests (#573)

pull/575/head
Pier CeccoPierangioliEugenio 3 months ago committed by GitHub
parent
commit
457796908f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 4
      .github/workflows/testing.yml
  2. 17
      libs/pyTermTk/TermTk/TTkAbstract/abstractscrollview.py
  3. 7
      libs/pyTermTk/TermTk/TTkCore/timer.py
  4. 65
      libs/pyTermTk/TermTk/TTkCore/timer_interface.py
  5. 39
      libs/pyTermTk/TermTk/TTkCore/timer_pyodide.py
  6. 13
      libs/pyTermTk/TermTk/TTkCore/timer_unix.py
  7. 7
      libs/pyTermTk/TermTk/TTkTestWidgets/tominspector.py
  8. 7
      libs/pyTermTk/pyproject.toml

4
.github/workflows/testing.yml

@ -55,10 +55,10 @@ jobs:
tools/check.import.sh
- name: Install dependencies
shell: bash
run: |
python -m pip install --upgrade pip
python -m pip install flake8 pytest
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
python -m pip install -e 'libs/pyTermTk[test]'
- name: Lint with flake8
run: |

17
libs/pyTermTk/TermTk/TTkAbstract/abstractscrollview.py

@ -503,7 +503,8 @@ class TTkAbstractScrollViewGridLayout(TTkGridLayout, TTkAbstractScrollViewInterf
return
self._excludeEvent = True
for widget in self.iterWidgets():
widget.viewMoveTo(x,y)
if isinstance(widget, TTkAbstractScrollViewInterface):
widget.viewMoveTo(x,y)
self._excludeEvent = False
self._viewOffsetX = x
self._viewOffsetY = y
@ -595,9 +596,10 @@ class TTkAbstractScrollViewGridLayout(TTkGridLayout, TTkAbstractScrollViewInterf
'''
w,h=0,0
for widget in self.iterWidgets():
ww,wh = widget.viewFullAreaSize()
w = max(w,ww)
h = max(h,wh)
if isinstance(widget, TTkAbstractScrollViewInterface):
ww,wh = widget.viewFullAreaSize()
w = max(w,ww)
h = max(h,wh)
return w,h
# Override this function
@ -609,9 +611,10 @@ class TTkAbstractScrollViewGridLayout(TTkGridLayout, TTkAbstractScrollViewInterf
'''
w,h=0,0
for widget in self.iterWidgets():
ww,wh = widget.viewDisplayedSize()
w = max(w,ww)
h = max(h,wh)
if isinstance(widget, TTkAbstractScrollViewInterface):
ww,wh = widget.viewDisplayedSize()
w = max(w,ww)
h = max(h,wh)
return w,h
def getViewOffsets(self) -> Tuple[int,int]:

7
libs/pyTermTk/TermTk/TTkCore/timer.py

@ -23,9 +23,12 @@
__all__ = ['TTkTimer']
import importlib.util
from typing import TYPE_CHECKING
from .timer_interface import _TTkTimer_Interface as TTkTimer
if importlib.util.find_spec('pyodideProxy'):
from .timer_pyodide import TTkTimer
from .timer_pyodide import _TTkTimer_Pyodide as TTkTimer
else:
from .timer_unix import TTkTimer
from .timer_unix import _TTkTimer_Unix as TTkTimer

65
libs/pyTermTk/TermTk/TTkCore/timer_interface.py

@ -0,0 +1,65 @@
# MIT License
#
# Copyright (c) 2021 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
__all__ = []
from typing import Callable,Optional,Protocol
from TermTk.TTkCore.signal import pyTTkSignal, pyTTkSlot
class _TTkTimer_Interface(Protocol):
'''Protocol defining the interface for timer implementations.'''
timeout: pyTTkSignal
def __init__(
self,
name: Optional[str] = None,
excepthook: Optional[Callable[[Exception], None]] = None) -> None:
'''Initialize timer with optional name and exception handler.
:param name: Optional name for the timer
:type name: str, optional
:param excepthook: Optional callback for exception handling
:type excepthook: Callable[[Exception], None], optional
'''
...
def quit(self) -> None:
'''Stop the timer and cleanup resources.'''
...
def run(self) -> None:
'''Main timer loop (typically runs in a thread).'''
...
def start(self, sec: float = 0.0) -> None:
'''Start the timer with specified interval.
:param sec: Interval in seconds
:type sec: float
'''
...
def stop(self) -> None:
'''Stop the timer without cleanup.'''
...

39
libs/pyTermTk/TermTk/TTkCore/timer_pyodide.py

@ -22,17 +22,18 @@
from __future__ import annotations
__all__ = ['TTkTimer']
__all__ = []
from typing import Optional,Callable,Dict
from TermTk.TTkCore.helper import TTkHelper
from TermTk.TTkCore.signal import pyTTkSlot, pyTTkSignal
from TermTk.TTkCore.timer_interface import _TTkTimer_Interface
import pyodideProxy
import pyodideProxy # type: ignore[import-not-found]
class TTkTimer():
_timers:Dict[int,TTkTimer] = {}
class _TTkTimer_Pyodide(_TTkTimer_Interface):
_timers:Dict[int,_TTkTimer_Pyodide] = {}
_uid = 0
__slots__ = (
@ -50,38 +51,38 @@ class TTkTimer():
self._running = True
self._timer = None
self._id = TTkTimer._uid
TTkTimer._uid +=1
TTkTimer._timers[self._id] = self
self._id = _TTkTimer_Pyodide._uid
_TTkTimer_Pyodide._uid +=1
_TTkTimer_Pyodide._timers[self._id] = self
@staticmethod
def triggerTimerId(tid):
if tid in TTkTimer._timers:
def triggerTimerId(tid) -> None:
if tid in _TTkTimer_Pyodide._timers:
# Little hack to avoid deadloop in pyodide
if rw := TTkHelper._rootWidget:
rw._paintEvent.set()
TTkTimer._timers[tid].timeout.emit()
_TTkTimer_Pyodide._timers[tid].timeout.emit()
@staticmethod
def pyodideQuit():
for timer in TTkTimer._timers:
TTkTimer._timers[timer].timeout.clearAll()
TTkTimer._timers[timer]._running = False
TTkTimer._timers[timer].quit()
TTkTimer._timers = {}
def pyodideQuit() -> None:
for timer in _TTkTimer_Pyodide._timers:
_TTkTimer_Pyodide._timers[timer].timeout.clearAll()
_TTkTimer_Pyodide._timers[timer]._running = False
_TTkTimer_Pyodide._timers[timer].quit()
_TTkTimer_Pyodide._timers = {}
def quit(self):
def quit(self) -> None:
pass
@pyTTkSlot(float)
def start(self, sec=0.0):
def start(self, sec=0.0) -> None:
self.stop()
if self._running:
self._timer = pyodideProxy.setTimeout(int(sec*1000), self._id)
# pyodideProxy.consoleLog(f"Timer {self._timer}")
@pyTTkSlot()
def stop(self):
def stop(self) -> None:
# pyodideProxy.consoleLog(f"Timer {self._timer}")
if self._timer:
pyodideProxy.stopTimeout(self._timer)

13
libs/pyTermTk/TermTk/TTkCore/timer_unix.py

@ -20,7 +20,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
__all__ = ['TTkTimer']
__all__ = []
from typing import Optional,Callable
@ -28,8 +28,9 @@ import threading
from TermTk.TTkCore.signal import pyTTkSlot, pyTTkSignal
from TermTk.TTkCore.helper import TTkHelper
from TermTk.TTkCore.timer_interface import _TTkTimer_Interface
class TTkTimer(threading.Thread):
class _TTkTimer_Unix(threading.Thread, _TTkTimer_Interface):
__slots__ = (
'timeout', '_delay',
'_timer', '_quit', '_start',
@ -51,14 +52,14 @@ class TTkTimer(threading.Thread):
super().__init__(name=name)
TTkHelper.quitEvent.connect(self.quit)
def quit(self):
def quit(self) -> None:
TTkHelper.quitEvent.disconnect(self.quit)
self.timeout.clear()
self._quit.set()
self._timer.set()
self._start.set()
def run(self):
def run(self) -> None:
try:
while not self._quit.is_set():
self._start.wait()
@ -73,7 +74,7 @@ class TTkTimer(threading.Thread):
raise e
@pyTTkSlot(float)
def start(self, sec:float=0.0):
def start(self, sec:float=0.0) -> None:
self._delay = sec
self._timer.set()
self._timer.clear()
@ -82,5 +83,5 @@ class TTkTimer(threading.Thread):
super().start()
@pyTTkSlot()
def stop(self):
def stop(self) -> None:
self._timer.set()

7
libs/pyTermTk/TermTk/TTkTestWidgets/tominspector.py

@ -151,7 +151,12 @@ class TTkTomInspector(TTkContainer):
self.setLayout(layout)
self._domTree = TTkTree()
self._domTree.setHeaderLabels(["Object", "Class", "Visibility", "Layout"])
self._domTree.setHeaderLabels([
TTkString("Object"),
TTkString("Class"),
TTkString("Visibility"),
TTkString("Layout")
])
if TTkHelper._rootWidget:
self._domTree.addTopLevelItem(TTkTomInspector._getTomTreeItem(TTkHelper._rootWidget._widgetItem))

7
libs/pyTermTk/pyproject.toml

@ -39,6 +39,13 @@
[tool.setuptools.packages.find]
where = ["."]
[project.optional-dependencies]
test = [
"pytest>=8.3.4",
"flake8>=7.2.0",
"mypy>=1.15.0"
]
[tool.setuptools.dynamic]
version = {attr = "TermTk.__version__"}

Loading…
Cancel
Save