diff --git a/TermTk/TTkAbstract/abstracttablemodel.py b/TermTk/TTkAbstract/abstracttablemodel.py index 2b969229..7b2ca75c 100644 --- a/TermTk/TTkAbstract/abstracttablemodel.py +++ b/TermTk/TTkAbstract/abstracttablemodel.py @@ -37,11 +37,19 @@ class TTkAbstractTableModel(): def rowCount(self) -> int: raise NotImplementedError() + def columnCount(self) -> int: raise NotImplementedError() + def data(self, row:int, col:int) -> TTkString: return TTkString() - def headerData(self, col:int, orientation:TTkK.Direction) -> TTkString: + + def headerData(self, pos:int, orientation:TTkK.Direction) -> TTkString: + if orientation==TTkK.HORIZONTAL: + return TTkString(str(pos)) + elif orientation==TTkK.VERTICAL: + return TTkString(str(pos)) return TTkString() + def sort(self, col:int, order) -> None: pass diff --git a/TermTk/TTkWidgets/TTkModelView/__init__.py b/TermTk/TTkWidgets/TTkModelView/__init__.py index acb9c5c0..08e63ff5 100644 --- a/TermTk/TTkWidgets/TTkModelView/__init__.py +++ b/TermTk/TTkWidgets/TTkModelView/__init__.py @@ -4,3 +4,6 @@ from .treewidgetitem import * from .filetree import * from .filetreewidget import * from .filetreewidgetitem import * +from .table import * +from .tablewidget import * +from .tablewidgetitem import * diff --git a/TermTk/TTkWidgets/TTkModelView/table.py b/TermTk/TTkWidgets/TTkModelView/table.py new file mode 100644 index 00000000..253dba5c --- /dev/null +++ b/TermTk/TTkWidgets/TTkModelView/table.py @@ -0,0 +1,71 @@ +# MIT License +# +# Copyright (c) 2024 Eugenio Parodi +# +# 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__ = ['TTkTable'] + +from TermTk.TTkCore.constant import TTkK +from TermTk.TTkWidgets.TTkModelView.tablewidget import TTkTableWidget +from TermTk.TTkAbstract.abstractscrollarea import TTkAbstractScrollArea + +class TTkTable(TTkAbstractScrollArea): + __slots__ = ( + '_tableView', + # Forwarded Signals + 'itemActivated', 'itemChanged', 'itemClicked', 'itemExpanded', 'itemCollapsed', 'itemDoubleClicked', + # Forwarded Methods + 'setModel', 'setSortingEnabled', + 'resizeColumnsToContents', + + # Forwarded Methods From TTkTree + 'setHeaderLabels', + 'setColumnWidth', 'resizeColumnToContents', + # 'appendItem', 'setAlignment', 'setColumnColors', 'setColumnSize', 'setHeader', + 'addTopLevelItem', 'addTopLevelItems', 'takeTopLevelItem', 'topLevelItem', 'indexOfTopLevelItem', 'selectedItems', 'clear' ) + + def __init__(self, *, parent=None, visible=True, **kwargs): + super().__init__(parent=parent, visible=visible, **kwargs) + self._tableView = kwargs.get('TableWidget',TTkTableWidget(**kwargs)) + self.setViewport(self._tableView) + self.setFocusPolicy(TTkK.ClickFocus) + + self.setModel = self._tableView.setModel + self.setSortingEnabled = self._tableView.setSortingEnabled + self.resizeColumnsToContents = self._tableView.resizeColumnsToContents + + # # Forward the signal + # self.itemActivated = self._tableView.itemActivated + # self.itemChanged = self._tableView.itemChanged + # self.itemClicked = self._tableView.itemClicked + # self.itemDoubleClicked = self._tableView.itemDoubleClicked + + # # Forwarded Methods + # #self.setAlignment = self._tableView.setAlignment + # #self.setHeader = self._tableView.setHeader + # self.setHeaderLabels = self._tableView.setHeaderLabels + # #self.setColumnSize = self._tableView.setColumnSize + # #self.setColumnColors = self._tableView.setColumnColors + # #self.appendItem = self._tableView.appendItem + # self.selectedItems = self._tableView.selectedItems + # self.setColumnWidth = self._tableView.setColumnWidth + # self.resizeColumnToContents = self._tableView.resizeColumnToContents + + # self.clear = self._tableView.clear diff --git a/TermTk/TTkWidgets/TTkModelView/tablewidget.py b/TermTk/TTkWidgets/TTkModelView/tablewidget.py new file mode 100644 index 00000000..5f0042d1 --- /dev/null +++ b/TermTk/TTkWidgets/TTkModelView/tablewidget.py @@ -0,0 +1,310 @@ +# MIT License +# +# Copyright (c) 2024 Eugenio Parodi +# +# 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__ = ['TTkTableWidget'] + +from TermTk.TTkCore.log import TTkLog +from TermTk.TTkCore.cfg import TTkCfg +from TermTk.TTkCore.constant import TTkK +from TermTk.TTkCore.string import TTkString +from TermTk.TTkCore.color import TTkColor +# from TermTk.TTkWidgets.TTkModelView.tablewidgetitem import TTkTableWidgetItem +from TermTk.TTkAbstract.abstractscrollview import TTkAbstractScrollView +from TermTk.TTkAbstract.abstracttablemodel import TTkAbstractTableModel +from TermTk.TTkCore.signal import pyTTkSignal, pyTTkSlot + +class _DefaultTableModel(TTkAbstractTableModel): + def __init__(self, **args): + super().__init__(**args) + def rowCount(self): + return 15 + def columnCount(self): + return 10 + def data(self, row, col): + return f"{row}x{col}" + +class TTkTableWidget(TTkAbstractScrollView): + '''TTkTableWidget''' + + classStyle = { + 'default': { + 'color': TTkColor.RST, + 'lineColor': TTkColor.fg("#444444"), + 'headerColor': TTkColor.fg("#ffffff")+TTkColor.bg("#444444")+TTkColor.BOLD, + 'selectedColor': TTkColor.fg("#ffff88")+TTkColor.bg("#000066")+TTkColor.BOLD, + 'separatorColor': TTkColor.fg("#555555")+TTkColor.bg("#444444")}, + 'disabled': { + 'color': TTkColor.fg("#888888"), + 'lineColor': TTkColor.fg("#888888"), + 'headerColor': TTkColor.fg("#888888"), + 'selectedColor': TTkColor.fg("#888888"), + 'separatorColor': TTkColor.fg("#888888")}, + } + + __slots__ = ( '_tableModel', + '_vHeaderSize', + '_colsPos', '_rowsPos', + '_selectedId', '_selected', '_separatorSelected', + '_sortColumn', '_sortOrder', + # Signals + # 'itemChanged', 'itemClicked', 'itemDoubleClicked', 'itemExpanded', 'itemCollapsed', 'itemActivated' + ) + + def __init__(self, **kwargs) -> None: + # Signals + # self.itemActivated = pyTTkSignal(TTkTableWidgetItem, int) + # self.itemChanged = pyTTkSignal(TTkTableWidgetItem, int) + # self.itemClicked = pyTTkSignal(TTkTableWidgetItem, int) + # self.itemDoubleClicked = pyTTkSignal(TTkTableWidgetItem, int) + # self.itemExpanded = pyTTkSignal(TTkTableWidgetItem) + # self.itemCollapsed = pyTTkSignal(TTkTableWidgetItem) + + self._tableModel = _DefaultTableModel() + self._refreshLayout() + self._selected = None + self._selectedId = None + self._separatorSelected = None + self._sortColumn = -1 + self._sortOrder = TTkK.AscendingOrder + super().__init__(**kwargs) + self.setMinimumHeight(1) + self.setFocusPolicy(TTkK.ClickFocus) + # self._rootItem = TTkTableWidgetItem(expanded=True) + # self.clear() + self.setPadding(1,0,0,0) + self.viewChanged.connect(self._viewChangedHandler) + + def _refreshLayout(self): + self._vHeaderSize = 1+max(len(self._tableModel.headerData(_p, TTkK.VERTICAL)) for _p in range(self._tableModel.rowCount()) ) + self._colsPos = [(1+x)*10 for x in range(self._tableModel.columnCount())] + self._rowsPos = [(1+x)*2 for x in range(self._tableModel.rowCount())] + + # Overridden function + def viewFullAreaSize(self) -> tuple[int, int]: + w = self._vHeaderSize+self._colsPos[-1] + h = 1+self._rowsPos[-1] + return w,h + + # Overridden function + def viewDisplayedSize(self) -> tuple[int, int]: + return self.size() + + @pyTTkSlot() + def _viewChangedHandler(self) -> None: + x,y = self.getViewOffsets() + self.layout().setOffset(-x,-y) + + def setModel(self, model) -> None: + self._tableModel = model + self._refreshLayout() + self.viewChanged.emit() + + def setSortingEnabled(self, enable) -> None: + pass + def resizeColumnsToContents(self) -> None: + pass + + def focusOutEvent(self) -> None: + self._separatorSelected = None + + def mousePressEvent(self, evt) -> bool: + x,y = evt.x, evt.y + ox, oy = self.getViewOffsets() + vx = self._vHeaderSize + x += ox-vx + self._separatorSelected = None + + # Handle Header Events + if y == 0: + for i, c in enumerate(self._colsPos): + if x == c: + # I-th separator selected + self._separatorSelected = i + self.update() + break + elif x < c: + # # I-th header selected + # order = not self._sortOrder if self._sortColumn == i else TTkK.AscendingOrder + # self.sortItems(i, order) + break + return True + # # Handle Tree/Table Events + # y += oy-1 + # if 0 <= y < len(self._cache): + # item = self._cache[y].item + # level = self._cache[y].level + # # check if the expand button is pressed with +-1 tollerance + # if level*2 <= x < level*2+3 and \ + # ( item.childIndicatorPolicy() == TTkK.DontShowIndicatorWhenChildless and item.children() or + # item.childIndicatorPolicy() == TTkK.ShowIndicator ): + # item.setExpanded(not item.isExpanded()) + # if item.isExpanded(): + # self.itemExpanded.emit(item) + # else: + # self.itemCollapsed.emit(item) + # else: + # if self._selected: + # self._selected.setSelected(False) + # self._selectedId = y + # self._selected = item + # self._selected.setSelected(True) + # col = -1 + # for i, c in enumerate(self._columnsPos): + # if x < c: + # col = i + # break + # self.itemClicked.emit(item, col) + # self.update() + return True + + def mouseDragEvent(self, evt) -> bool: + ''' + :: + + columnPos (Selected = 2) + 0 1 2 3 4 + ----|-------|--------|----------|---| + Mouse (Drag) Pos + ^ + I consider at least 4 char (3+1) as spacing + Min Selected Pos = (Selected+1) * 4 + + ''' + if self._separatorSelected is not None: + x,y = evt.x, evt.y + ox, oy = self.getViewOffsets() + vx = self._vHeaderSize + y += oy + x += ox-vx + ss = self._separatorSelected + pos = max((ss+1)*4, x) + diff = pos - self._colsPos[ss] + # Align the previous Separators if pushed + for i in range(ss): + self._colsPos[i] = min(self._colsPos[i], pos-(ss-i)*4) + # Align all the other Separators relative to the selection + for i in range(ss, len(self._colsPos)): + self._colsPos[i] += diff + # self._alignWidgets() + self.viewChanged.emit() + self.update() + return True + return False + + def paintEvent(self, canvas) -> None: + style = self.currentStyle() + + color= style['color'] + lineColor= style['lineColor'] + headerColor= style['headerColor'] + selectedColor= style['selectedColor'] + separatorColor= style['separatorColor'] + + ox,oy = self.getViewOffsets() + w,h = self.size() + + rows = self._tableModel.rowCount() + cols = self._tableModel.columnCount() + rp = self._rowsPos + cp = self._colsPos + vx = self._vHeaderSize + + # Draw Lines + sliceCol=list(zip([-1]+cp,cp)) + sliceRow=list(zip([0]+rp,rp)) + for row in range(rows): + ya,yb = sliceRow[row] + if ya>h+oy: break + if ybw+ox: break + if xbh+oy: break + if yb h : break + if y < 1: continue + if row +# +# 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__ = [] diff --git a/TermTk/TTkWidgets/TTkModelView/treewidget.py b/TermTk/TTkWidgets/TTkModelView/treewidget.py index 24131555..2fb88fdf 100644 --- a/TermTk/TTkWidgets/TTkModelView/treewidget.py +++ b/TermTk/TTkWidgets/TTkModelView/treewidget.py @@ -50,7 +50,8 @@ class TTkTreeWidget(TTkAbstractScrollView): 'separatorColor': TTkColor.fg("#888888")}, } - __slots__ = ( '_rootItem', '_header', '_columnsPos', '_cache', + __slots__ = ( '_rootItem', '_cache', + '_header', '_columnsPos', '_selectedId', '_selected', '_separatorSelected', '_sortColumn', '_sortOrder', # Signals diff --git a/tests/t.generic/test.generic.008.class.cmp.py b/tests/t.generic/test.generic.008.class.cmp.py new file mode 100755 index 00000000..d73c4c84 --- /dev/null +++ b/tests/t.generic/test.generic.008.class.cmp.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 + +# MIT License +# +# Copyright (c) 2023 Eugenio Parodi +# +# 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. + +class A(): + def __init__(self,a,b) -> None: + self.a = a + self.b = b + + def __eq__(self, value: object) -> bool: + print(f"{self=},{value=}") + return self.a==value.a and self.b==value.b + + +a = A(1,2) +b = a +c = A(1,2) +d = A(1,3) + +print(f"{(a==b)=}") +print(f"{(a==c)=}") +print(f"{(a==d)=}") +print(f"{(a is b)=}") +print(f"{(a is c)=}") +print(f"{(a is d)=}") \ No newline at end of file diff --git a/tests/t.ui/test.ui.032.table.01.py b/tests/t.ui/test.ui.032.table.01.py index 893920d3..2642cf88 100755 --- a/tests/t.ui/test.ui.032.table.01.py +++ b/tests/t.ui/test.ui.032.table.01.py @@ -36,7 +36,7 @@ import TermTk as ttk class MyTableModel(ttk.TTkAbstractTableModel): def __init__(self, mylist, header, *args): - ttk.TTkAbstractTableModel.__init__(self, *args) + super().__init__(*args) self.mylist = mylist self.header = header def rowCount(self): @@ -48,7 +48,7 @@ class MyTableModel(ttk.TTkAbstractTableModel): def headerData(self, col, orientation): if orientation == ttk.TTkK.HORIZONTAL: return self.header[col] - return super().headerData(self, col, orientation) + return super().headerData(col, orientation) def sort(self, col, order): """sort table by given column number col""" # self.emit(SIGNAL("layoutAboutToBeChanged()")) @@ -120,7 +120,8 @@ data_list = [ ('TRIETHYLAMINE', 89.5, -114.7, 0.726), ('TRIFLUOROACETIC ACID', 71.8, -15.3, 1.489), ('WATER', 100.0, 0.0, 1.0), -('XYLENES', 139.1, -47.8, 0.86) +('XYLENES', 139.1, -47.8, 0.86), +('!!!END!!!', 123.4, -5432.1, 0.123) ] ttk.TTkLog.use_default_file_logging() @@ -131,19 +132,22 @@ args = parser.parse_args() root = ttk.TTk() if args.f: - rootTree1 = root + rootTable = root root.setLayout(ttk.TTkGridLayout()) else: - rootTree1 = ttk.TTkWindow(parent=root,pos = (0,0), size=(150,40), title="Test Tree 1", layout=ttk.TTkGridLayout(), border=True) + rootTable = ttk.TTkWindow(parent=root,pos = (0,0), size=(150,40), title="Test Table 1", layout=ttk.TTkGridLayout(), border=True) -table = ttk.TTkTable(parent=rootTree1) +splitter = ttk.TTkSplitter(parent=rootTable,orientation=ttk.TTkK.VERTICAL) + +table = ttk.TTkTable(parent=splitter) table_model = MyTableModel(data_list, header) -table_view = ttk.TTkTable() -table_view.setModel(table_model) +table.setModel(table_model) # set column width to fit contents (set font first!) -table_view.resizeColumnsToContents() +table.resizeColumnsToContents() # enable sorting -table_view.setSortingEnabled(True) +table.setSortingEnabled(True) + +splitter.addWidget(ttk.TTkLogViewer(),size=10,title="LOGS") root.mainloop() \ No newline at end of file diff --git a/tests/timeit/25.comparison.03.py b/tests/timeit/25.comparison.03.py new file mode 100755 index 00000000..48131ac4 --- /dev/null +++ b/tests/timeit/25.comparison.03.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 + +# MIT License +# +# Copyright (c) 2023 Eugenio Parodi +# +# 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. + +import timeit, pickle + +class ObjA(): + __slots__ = ('a','b','c','d') + def __init__(self,a,b,c,d) -> None: + self.a=a + self.b=b + self.c=c + self.d=d + +class ObjA1(ObjA): + def __eq__(self, other): + if other is None: return False + # return id(other) == id(self) + return id(other) == id(self) or ( + # return other is self or ( + # return ( + self.a == other.a and + self.b == other.b and + self.c == other.c and + self.d == other.d ) + +class ObjA2(ObjA): + def __eq__(self, other): + if other is None: return False + return id(other) == id(self) or ( + #return other is self or ( + (self.a, self.b, self.c, self.d ) == + (other.a,other.b,other.c,other.d) ) + +class ObjA3(ObjA): + __slots__ = ('rec') + def __init__(self, a, b, c, d) -> None: + super().__init__(a, b, c, d) + self.rec = (self.a, self.b, self.c, self.d ) + def __eq__(self, other): + if other is None: return False + return id(other) == id(self) or ( + # return other is self or ( + self.rec == other.rec) + +oa1_1 = ObjA1(1,'asd123456789abcdefghijklmnopqrstuvwxyz',3.123456,'123456789123456789123456789123456789') +oa1_2 = ObjA1(1,'asd123456789abcdefghijklmnopqrstuvwxyz',3.123456,'123456789123456789123456789123456789') +oa1_3 = ObjA1(1,'asd123456789abcdefghijklmnopqrstuvwxyz',3.123456,'123456789123456789123456789123456789') +oa1_4 = ObjA1(1,'asd123456789abcdefghijklmnopqrstuvwxyz',3.123456,'123456789123456789123456789123456789') +oa2_1 = ObjA2(1,'asd123456789abcdefghijklmnopqrstuvwxyz',3.123456,'123456789123456789123456789123456789') +oa2_2 = ObjA2(1,'asd123456789abcdefghijklmnopqrstuvwxyz',3.123456,'123456789123456789123456789123456789') +oa2_3 = ObjA2(1,'asd123456789abcdefghijklmnopqrstuvwxyz',3.123456,'123456789123456789123456789123456789') +oa2_4 = ObjA2(1,'asd123456789abcdefghijklmnopqrstuvwxyz',3.123456,'123456789123456789123456789123456789') +oa3_1 = ObjA3(1,'asd123456789abcdefghijklmnopqrstuvwxyz',3.123456,'123456789123456789123456789123456789') +oa3_2 = ObjA3(1,'asd123456789abcdefghijklmnopqrstuvwxyz',3.123456,'123456789123456789123456789123456789') +oa3_3 = ObjA3(1,'asd123456789abcdefghijklmnopqrstuvwxyz',3.123456,'123456789123456789123456789123456789') +oa3_4 = ObjA3(1,'asd123456789abcdefghijklmnopqrstuvwxyz',3.123456,'123456789123456789123456789123456789') + +oa1_1d = ObjA1(1,'asd123456789abcdefghijklmnopqrstuvwxyz',3.123456,'1234567891234567891234567891234567891') +oa1_2d = ObjA1(1,'asd123456789abcdefghijklmnopqrstuvwxyz',3.123456,'1234567891234567891234567891234567892') +oa1_3d = ObjA1(1,'asd123456789abcdefghijklmnopqrstuvwxyz',3.123456,'1234567891234567891234567891234567893') +oa1_4d = ObjA1(1,'asd123456789abcdefghijklmnopqrstuvwxyz',3.123456,'1234567891234567891234567891234567894') +oa2_1d = ObjA2(1,'asd123456789abcdefghijklmnopqrstuvwxyz',3.123456,'1234567891234567891234567891234567895') +oa2_2d = ObjA2(1,'asd123456789abcdefghijklmnopqrstuvwxyz',3.123456,'1234567891234567891234567891234567896') +oa2_3d = ObjA2(1,'asd123456789abcdefghijklmnopqrstuvwxyz',3.123456,'1234567891234567891234567891234567897') +oa2_4d = ObjA2(1,'asd123456789abcdefghijklmnopqrstuvwxyz',3.123456,'1234567891234567891234567891234567898') +oa3_1d = ObjA3(1,'asd123456789abcdefghijklmnopqrstuvwxyz',3.123456,'1234567891234567891234567891234567895') +oa3_2d = ObjA3(1,'asd123456789abcdefghijklmnopqrstuvwxyz',3.123456,'1234567891234567891234567891234567896') +oa3_3d = ObjA3(1,'asd123456789abcdefghijklmnopqrstuvwxyz',3.123456,'1234567891234567891234567891234567897') +oa3_4d = ObjA3(1,'asd123456789abcdefghijklmnopqrstuvwxyz',3.123456,'1234567891234567891234567891234567898') + +print(f"{len(pickle.dumps(oa1_1))=}") +print(f"{len(pickle.dumps(oa2_1))=}") +print(f"{len(pickle.dumps(oa3_1))=}") +print(f"diff: {len(pickle.dumps(oa3_1))-len(pickle.dumps(oa1_1))}") + +def test1(): return oa1_1==oa1_1==oa1_1==oa1_1 +def test2(): return oa1_1==oa1_2==oa1_3==oa1_4 +def test3(): return oa2_1==oa2_1==oa2_1==oa2_1 +def test4(): return oa2_1==oa2_2==oa2_3==oa2_4 +def test5(): return oa3_1==oa3_1==oa3_1==oa3_1 +def test6(): return oa3_1==oa3_2==oa3_3==oa3_4 + +def test7(): return oa1_1==oa1_1==oa1_1==oa1_1d +def test8(): return oa1_1==oa1_2==oa1_3==oa1_4d +def test9(): return oa2_1==oa2_1==oa2_1==oa2_1d +def test10(): return oa2_1==oa2_2==oa2_3==oa2_4d +def test11(): return oa3_1==oa3_1==oa3_1==oa3_1d +def test12(): return oa3_1==oa3_2==oa3_3==oa3_4d + +def test13(): return oa1_1d==oa1_1==oa1_1==oa1_1 +def test14(): return oa1_1d==oa1_2==oa1_3==oa1_4 +def test15(): return oa2_1d==oa2_1==oa2_1==oa2_1 +def test16(): return oa2_1d==oa2_2==oa2_3==oa2_4 +def test17(): return oa3_1d==oa3_1==oa3_1==oa3_1 +def test18(): return oa3_1d==oa3_2==oa3_3==oa3_4 + + +loop = 300000 + +a = {} + +iii = 1 +while (testName := f'test{iii}') and (testName in globals()): + result = timeit.timeit(f'{testName}(*a)', globals=globals(), number=loop) + # print(f"test{iii}) fps {loop / result :.3f} - s {result / loop:.10f} - {result / loop} {globals()[testName](*a)}") + print(f"test{iii:02}) | {result / loop:.10f} sec. | {loop / result : 15.3f} Fps ╞╡-> {globals()[testName](*a)}") + iii+=1