From 833005acd115f2a5cb467b614ff208bda013c043 Mon Sep 17 00:00:00 2001 From: Pier CeccoPierangioliEugenio Date: Tue, 17 Jun 2025 09:20:54 +0100 Subject: [PATCH] chore: improve typing (#417) --- apps/perspectivator/perspectivator.wand.py | 2 + libs/pyTermTk/TermTk/TTkCore/constant.py | 4 +- libs/pyTermTk/TermTk/TTkCore/string.py | 49 ++++++----- libs/pyTermTk/TermTk/TTkWidgets/container.py | 8 +- libs/pyTermTk/TermTk/TTkWidgets/widget.py | 87 +++++++++++++------- tools/check.import.sh | 6 +- tools/image/example.projection.2.py | 1 + 7 files changed, 95 insertions(+), 62 deletions(-) diff --git a/apps/perspectivator/perspectivator.wand.py b/apps/perspectivator/perspectivator.wand.py index 7205fd82..17b2a38e 100644 --- a/apps/perspectivator/perspectivator.wand.py +++ b/apps/perspectivator/perspectivator.wand.py @@ -26,6 +26,8 @@ import argparse from dataclasses import dataclass from typing import Optional,Tuple,List,Dict +from PIL import ImageDraw, ImageFilter + import numpy as np from wand.image import Image diff --git a/libs/pyTermTk/TermTk/TTkCore/constant.py b/libs/pyTermTk/TermTk/TTkCore/constant.py index f87dd379..57d462ff 100644 --- a/libs/pyTermTk/TermTk/TTkCore/constant.py +++ b/libs/pyTermTk/TermTk/TTkCore/constant.py @@ -22,6 +22,8 @@ __all__ = ['TTkConstant', 'TTkK'] +from enum import IntEnum + class TTkConstant: '''Class container of all the constants used in :mod:`~TermTk`''' @@ -56,7 +58,7 @@ class TTkConstant: ColorModifier = 0x08 '''The :py:class:`TTkColor` include a color modifier based on :py:class:`TTkColorModifier`''' - class FocusPolicy(int): + class FocusPolicy(IntEnum): ''' This Class type defines the various policies a widget can have with respect to acquiring keyboard focus. diff --git a/libs/pyTermTk/TermTk/TTkCore/string.py b/libs/pyTermTk/TermTk/TTkCore/string.py index f70c6402..f0886b64 100644 --- a/libs/pyTermTk/TermTk/TTkCore/string.py +++ b/libs/pyTermTk/TermTk/TTkCore/string.py @@ -20,18 +20,15 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +from __future__ import annotations + __all__ = ['TTkString'] import os import re import unicodedata from types import GeneratorType -from typing import Any - -try: - from typing import Self -except: - class Self(): pass +from typing import Any, Optional, Union, List, Tuple from TermTk.TTkCore.cfg import TTkCfg from TermTk.TTkCore.constant import TTkK @@ -69,11 +66,13 @@ class TTkString(): unicodeWideOverflowColor = TTkColor.fg("#888888")+TTkColor.bg("#000088") __slots__ = ('_text','_colors','_baseColor','_hasTab','_hasSpecialWidth') - + _text:str + _colors:List[TTkColor] + _baseColor:TTkColor def __init__(self, - text:str="", - color:TTkColor=None) -> None: - if issubclass(type(text), TTkString): + text:Union[str,TTkString]="", + color:Optional[TTkColor]=None) -> None: + if isinstance(text, TTkString): self._text = text._text self._colors = text._colors if color is None else [color]*len(self._text) self._baseColor = text._baseColor @@ -120,7 +119,7 @@ class TTkString(): def __str__(self) -> str: return self._text - def __add__(self, other:Self) -> Self: + def __add__(self, other:TTkString) -> TTkString: ret = TTkString() ret._baseColor = self._baseColor if isinstance(other, TTkString): @@ -142,7 +141,7 @@ class TTkString(): ret._baseColor = other return ret - def __radd__(self, other:Self) -> Self: + def __radd__(self, other:TTkString) -> TTkString: ret = TTkString() ret._baseColor = self._baseColor if isinstance(other, TTkString): @@ -180,7 +179,7 @@ class TTkString(): def __gt__(self, other): return self._text > other._text if issubclass(type(other),TTkString) else self._text > other def __ge__(self, other): return self._text >= other._text if issubclass(type(other),TTkString) else self._text >= other - def sameAs(self, other:Self) -> bool: + def sameAs(self, other:TTkString) -> bool: if not issubclass(type(other),TTkString): return False return ( self==other and @@ -190,7 +189,7 @@ class TTkString(): def isdigit(self) -> bool: return self._text.isdigit() - def lstrip(self, ch:str) -> Self: + def lstrip(self, ch:str) -> TTkString: ret = TTkString() ret._text = self._text.lstrip(ch) ret._colors = self._colors[-len(ret._text):] @@ -199,7 +198,7 @@ class TTkString(): def charAt(self, pos:int) -> str: return self._text[pos] - def setCharAt(self, pos:int, char:str) -> Self: + def setCharAt(self, pos:int, char:str) -> TTkString: self._text = self._text[:pos]+char+self._text[pos+1:] self._checkWidth() return self @@ -209,11 +208,11 @@ class TTkString(): return TTkColor() return self._colors[pos] - def setColorAt(self, pos, color) -> Self: + def setColorAt(self, pos, color) -> TTkString: self._colors[pos] = color return self - def tab2spaces(self, tabSpaces=4) -> Self: + def tab2spaces(self, tabSpaces=4) -> TTkString: '''Return the string representation with the tabs (converted in spaces) trimmed and aligned''' if not self._hasTab: return self ret = TTkString() @@ -327,7 +326,7 @@ class TTkString(): return out return out+str(TTkColor.RST) - def align(self, width=None, color=TTkColor.RST, alignment=TTkK.NONE) -> Self: + def align(self, width=None, color=TTkColor.RST, alignment=TTkK.NONE) -> TTkString: ''' Align the string :param width: the new width @@ -389,7 +388,7 @@ class TTkString(): return ret - def extractShortcuts(self) -> Self: + def extractShortcuts(self) -> Tuple[TTkString,List[str]]: def _chGenerator(): for ch,color in zip(self._text,self._colors): yield ch,color @@ -406,7 +405,7 @@ class TTkString(): _newColors.append(color) return TTkString._importString1(_newText,_newColors), _ret - def replace(self, *args, **kwargs) -> Self: + def replace(self, *args, **kwargs) -> TTkString: ''' **replace** (*old*, *new*, *count*) Replace "**old**" match with "**new**" string for "**count**" times @@ -454,7 +453,7 @@ class TTkString(): return ret - def completeColor(self, color:TTkColor, match=None, posFrom=None, posTo=None) -> Self: + def completeColor(self, color:TTkColor, match=None, posFrom=None, posTo=None) -> TTkString: ''' Complete the color of the entire string or a slice of it The Fg and/or Bg of the string is replaced with the selected Fg/Bg color only if missing @@ -495,7 +494,7 @@ class TTkString(): return ret - def setColor(self, color, match=None, posFrom=None, posTo=None) -> Self: + def setColor(self, color, match=None, posFrom=None, posTo=None) -> TTkString: ''' Set the color of the entire string or a slice of it If only the color is specified, the entire string is colorized @@ -531,7 +530,7 @@ class TTkString(): ret._colors += self._colors return ret - def substring(self, fr=None, to=None) -> Self: + def substring(self, fr=None, to=None) -> TTkString: ''' Return the substring :param fr: the starting of the slice, defaults to 0 @@ -546,7 +545,7 @@ class TTkString(): ret._fastCheckWidth(self._hasSpecialWidth) return ret - def split(self, separator ) -> list[Self]: + def split(self, separator ) -> list[TTkString]: ''' Split the string using a separator .. note:: Only a one char separator is currently supported @@ -599,7 +598,7 @@ class TTkString(): def getIndexes(self, char): return [i for i,c in enumerate(self._text) if c==char] - def join(self, strings:list[Self]) -> Self: + def join(self, strings:list[TTkString]) -> TTkString: ''' Join the input strings using the current as separator :param strings: the list of strings to be joined diff --git a/libs/pyTermTk/TermTk/TTkWidgets/container.py b/libs/pyTermTk/TermTk/TTkWidgets/container.py index 83befe8f..6722423d 100644 --- a/libs/pyTermTk/TermTk/TTkWidgets/container.py +++ b/libs/pyTermTk/TermTk/TTkWidgets/container.py @@ -22,7 +22,7 @@ __all__ = ['TTkContainer', 'TTkPadding'] -from typing import NamedTuple +from typing import NamedTuple, Optional from TermTk.TTkCore.constant import TTkK from TermTk.TTkCore.log import TTkLog @@ -104,8 +104,8 @@ class TTkContainer(TTkWidget): '_layout') def __init__(self, *, - layout:TTkLayout=None, - padding:TTkPadding = None, + layout:Optional[TTkLayout]=None, + padding:Optional[TTkPadding] = None, paddingTop:int = 0, paddingBottom:int = 0, paddingLeft:int = 0, @@ -381,7 +381,7 @@ class TTkContainer(TTkWidget): self._height - self._padt - self._padb) self.rootLayout().update() - def getWidgetByName(self, name: str) -> TTkWidget: + def getWidgetByName(self, name: str) -> Optional[TTkWidget]: ''' Return the widget from its name. diff --git a/libs/pyTermTk/TermTk/TTkWidgets/widget.py b/libs/pyTermTk/TermTk/TTkWidgets/widget.py index 807a9965..05097b91 100644 --- a/libs/pyTermTk/TermTk/TTkWidgets/widget.py +++ b/libs/pyTermTk/TermTk/TTkWidgets/widget.py @@ -20,14 +20,11 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -__all__ = ['TTkWidget'] +from __future__ import annotations -from typing import Callable, Any, List +__all__ = ['TTkWidget'] -try: - from typing import Self -except: - class Self(): pass +from typing import ( TYPE_CHECKING, Callable, Any, List, Optional, Tuple, Union, Dict ) from TermTk.TTkCore.cfg import TTkCfg, TTkGlbl from TermTk.TTkCore.constant import TTkK @@ -43,6 +40,9 @@ from TermTk.TTkTemplates.keyevents import TKeyEvents from TermTk.TTkLayouts.layout import TTkWidgetItem from TermTk.TTkCore.TTkTerm.inputmouse import TTkMouseEvent +if TYPE_CHECKING: + from TermTk import TTkContainer + class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents): ''' Widget sizes: @@ -122,25 +122,51 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents): #Signals 'focusChanged', 'sizeChanged', 'currentStyleChanged', 'closed') - def __init__(self, - parent:Self = None, - x:int=0, y:int=0, - width:int=0, height:int=0, - pos : tuple = None, - size : tuple = None, - maxSize : tuple = None, - maxWidth : int = 0x10000, - maxHeight: int = 0x10000, - minSize : tuple = None, - minWidth : int = 0x00000, - minHeight: int = 0x00000, - name : str = None, - visible : bool = True, - enabled : bool = True, - toolTip : TTkString = '', - style : dict = None, - addStyle : dict = None, - **kwargs) -> None: + _name:str + _parent:Optional[TTkContainer] + _x:int + _y:int + _width:int + _height:int + _maxw:int + _maxh:int + _minw:int + _minh:int + _focus:bool + _focus_policy:TTkK.FocusPolicy + _canvas:TTkCanvas + _widgetItem:TTkWidgetItem + _visible:bool + _pendingMouseRelease:bool + _enabled:bool + _style:Dict + _currentStyle:Dict + _toolTip:TTkString + _dropEventProxy:Any + _widgetCursor:Tuple[int,int] + _widgetCursorEnabled:bool + _widgetCursorType:int + + def __init__( + self, + parent:Optional[TTkContainer] = None, + x:int=0, y:int=0, + width:int=0, height:int=0, + pos : Optional[Tuple[int,int]] = None, + size : Optional[Tuple[int,int]] = None, + maxSize : Optional[Tuple[int,int]] = None, + maxWidth : int = 0x10000, + maxHeight: int = 0x10000, + minSize : Optional[Tuple[int,int]] = None, + minWidth : int = 0x00000, + minHeight: int = 0x00000, + name : Optional[str] = None, + visible : bool = True, + enabled : bool = True, + toolTip : Union[TTkString,str] = '', + style : Optional[Dict] = None, + addStyle : Optional[Dict] = None, + **kwargs) -> None: ''' :param name: the name of the widget, defaults to "" :type name: str, optional @@ -401,7 +427,7 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents): :param txt: the paste object :type txt: str ''' - return False + pass def _mouseEventParseChildren(self, evt:TTkMouseEvent) -> bool: return False @@ -813,14 +839,15 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents): _S_PRESSED = 0x20 _S_RELEASED = 0x40 - def style(self) -> dict: + def style(self) -> Dict: return self._style.copy() - def currentStyle(self) -> dict: + def currentStyle(self) -> Dict: return self._currentStyle - def setCurrentStyle(self, style) -> dict: - if style == self._currentStyle: return + def setCurrentStyle(self, style) -> None: + if style == self._currentStyle: + return self._currentStyle = style self.currentStyleChanged.emit(style) self.update() diff --git a/tools/check.import.sh b/tools/check.import.sh index 4634df7c..563b477d 100755 --- a/tools/check.import.sh +++ b/tools/check.import.sh @@ -8,6 +8,7 @@ __check(){ grep -v -e "import re" -e "import os" -e "import datetime" | grep -v \ -e "from dataclasses" \ + -e "from __future__ import annotations" \ -e "signal.py:from inspect import getfullargspec" \ -e "signal.py:from types import LambdaType" \ -e "signal.py:from threading import Lock" \ @@ -41,8 +42,8 @@ __check(){ -e "propertyanimation.py:from types import LambdaType" \ -e "propertyanimation.py:import time, math" \ -e "savetools.py:import importlib.util" \ - -e "savetools.py:import json" | - -e "TTkCore/color.py:from __future__ import annotations" | + -e "savetools.py:import json" \ + -e "TTkCore/constant.py:from enum import IntEnum" | grep -v \ -e "TTkTerm/input_mono.py:from time import time" \ -e "TTkTerm/input_mono.py:import platform" \ @@ -109,6 +110,7 @@ __check(){ -e "TTkTerminal/__init__.py:import importlib.util" \ -e "TTkTerminal/__init__.py:import platform" | grep -v \ + -e "TTkWidgets/widget.py:from __future__ import annotations" \ -e "TTkWidgets/tabwidget.py:from enum import Enum" \ -e "TTkModelView/__init__.py:from importlib.util import find_spec" \ -e "TTkModelView/tablemodelcsv.py:import csv" \ diff --git a/tools/image/example.projection.2.py b/tools/image/example.projection.2.py index b95649e8..93031569 100644 --- a/tools/image/example.projection.2.py +++ b/tools/image/example.projection.2.py @@ -1,4 +1,5 @@ import math +import numpy as np,array def project_3d_to_2d(square_3d, observer, look_at, fov=90, aspect_ratio=1, near=0.1, far=1000): """