Browse Source

Base of the TTkTerminal implementation

pull/150/head
Eugenio Parodi 3 years ago
parent
commit
56f7835327
  1. 2
      TermTk/TTkWidgets/TTkTerminal/__init__.py
  2. 171
      TermTk/TTkWidgets/TTkTerminal/terminal.py
  3. 1403
      TermTk/TTkWidgets/TTkTerminal/terminal_alt.py
  4. 1429
      TermTk/TTkWidgets/TTkTerminal/terminal_normal.py
  5. 46
      TermTk/TTkWidgets/TTkTerminal/vt102.py
  6. 2
      TermTk/TTkWidgets/__init__.py
  7. 3
      tests/test.pty.005.fork.py
  8. 66
      tests/test.pty.006.terminal.py
  9. 224
      tests/timeit/15.strings.01.re.loop.py
  10. 94
      tests/timeit/15.strings.02.re.py
  11. 151
      tests/timeit/16.dict.01.get.py

2
TermTk/TTkWidgets/TTkTerminal/__init__.py

@ -0,0 +1,2 @@
from .terminal import *
from .vt102 import *

171
TermTk/TTkWidgets/TTkTerminal/terminal.py

@ -0,0 +1,171 @@
# MIT License
#
# Copyright (c) 2023 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.
import os, pty, threading
import re
from select import select
from TermTk.TTkCore.canvas import TTkCanvas
from TermTk.TTkCore.color import TTkColor
from TermTk.TTkCore.log import TTkLog
from TermTk.TTkCore.constant import TTkK
from TermTk.TTkCore.cfg import TTkCfg
from TermTk.TTkCore.string import TTkString
from TermTk.TTkCore.signal import pyTTkSignal, pyTTkSlot
from TermTk.TTkCore.helper import TTkHelper
from TermTk.TTkGui.clipboard import TTkClipboard
from TermTk.TTkGui.textwrap1 import TTkTextWrap
from TermTk.TTkGui.textcursor import TTkTextCursor
from TermTk.TTkGui.textdocument import TTkTextDocument
from TermTk.TTkLayouts.gridlayout import TTkGridLayout
from TermTk.TTkAbstract.abstractscrollarea import TTkAbstractScrollArea
from TermTk.TTkAbstract.abstractscrollview import TTkAbstractScrollView, TTkAbstractScrollViewGridLayout
from TermTk.TTkWidgets.widget import TTkWidget
from .terminal_alt import _TTkTerminalAltScreen
from .terminal_normal import _TTkTerminalNormalScreen
from .vt102 import TTkVT102
__all__ = ['TTkTerminal']
class TTkTerminal(TTkWidget):
__slots__ = ('_shell', '_fd', '_inout', '_mode_normal'
'_buffer_lines', '_buffer_screen',
'_screen_current', '_screen_normal', '_screen_alt')
def __init__(self, *args, **kwargs):
self._shell = os.environ.get('SHELL', 'sh')
self._fd = None
self._mode_normal = True
self._buffer_lines = [TTkString()]
self._screen_normal = _TTkTerminalNormalScreen()
self._screen_alt = _TTkTerminalAltScreen()
self._screen_current = self._screen_normal
super().__init__(*args, **kwargs)
self.setFocusPolicy(TTkK.ClickFocus + TTkK.TabFocus)
def runShell(self, program=None):
self._shell = program if program else self._shell
pid, self._fd = pty.fork()
if pid == 0:
argv = [self._shell]
env = dict(TERM="screen", DISPLAY=":1")
os.execvpe(argv[0], argv, env)
else:
self._inout = os.fdopen(self._fd, "w+b", 0)
name = os.ttyname(self._fd)
TTkLog.debug(f"{self._fd=} {name}")
threading.Thread(target=self.loop,args=[self]).start()
# xterm escape sequences from:
# https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
# https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_
re_CURSOR = re.compile('^(\d*)(;?)(\d*)([@ABCDEFGIJKLMPSTXZ^`abcdeginqx])')
# https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_
# Basic Re for CSI Ps matches:
# CSI : Control Sequence Introducer "<ESC>[" = '\033['
# Ps : A single (usually optional) numeric parameter, composed of one or more digits.
# fn : the single char defining the function
re_CSI_Ps_fu = re.compile('^(\d*)([@ABCDEFGIJKLMPSTXZ^`abcdeginqx])')
re_CSI_Ps_Ps_fu = re.compile('^(\d*);(\d*)([Hf])')
re_DEC_SET_RST = re.compile('^\?(\d+)([lh])')
# re_CURSOR_1 = re.compile(r'^(\d+)([ABCDEFGIJKLMPSTXZHf])')
def _process_cursor_match(self, m):
y = ps = m.group(1)
sep = m.group(2)
x = m.group(3)
fn = m.group(4)
_ex = self._screen_current._CSI_MAP.get(fn,lambda a,b,c: None)
_ex(self._screen_current,y,x)
def loop(self, _):
while rs := select( [self._inout], [], [])[0]:
TTkLog.debug(f"Select - {rs=}")
for r in rs:
if r is self._inout:
try:
out = self._inout.read(10240)
except Exception as e:
TTkLog.error(f"Error: {e=}")
return
if out:
# TTkLog.debug(f'Eugenio->{out}')
sout = out.decode('utf-8','ignore')
sout = sout.split('\033[')
self._screen_current.pushLine(sout[0])
TTkLog.debug(f"{sout[0]=}")
for slice in sout[1:]:
if m := TTkTerminal.re_DEC_SET_RST.match(slice):
# l = len(m.group(0))
en = m.end()
ps = int(m.group(1))
sr = m.group(2)
if ps == 1049 and sr == 'l': # NORMAL SCREEN
self._screen_current = self._screen_normal
elif ps == 1049 and sr == 'h': # ALT SCREEN
self._screen_current = self._screen_alt
elif ps == 2004:
# Bracketedpaste ON
# Bracketedpaste OFF
pass
slice = slice[en:]
elif m := TTkTerminal.re_CURSOR.match(slice):
TTkLog.debug(f"{m.group(0)=} {m.group(1)=} {m.group(2)=}")
en = m.end()
self._process_cursor_match(m)
slice[en:]
else:
slice = '\033[' + slice.replace('\r','')
# TTkLog.debug(f'Eugenio->{slice}')
self._screen_current.pushLine(slice)
slice = slice.replace('\033','<ESC>').replace('\n','\\n')
TTkLog.debug(f"{slice=}")
self.update()
def mousePressEvent(self, evt):
return True
def keyEvent(self, evt):
# TTkLog.debug(f"Key: {evt.code=}")
TTkLog.debug(f"Key: {str(evt)=}")
self._inout.write(evt.code.encode())
if evt.type == TTkK.SpecialKey:
if evt.key == TTkK.Key_Enter:
TTkLog.debug(f"Key: Enter")
# self._inout.write(b'\n')
# self._inout.write(evt.code.encode())
else: # Input char
TTkLog.debug(f"Key: {evt.key=}")
# self._inout.write(evt.key.encode())
return True
def paintEvent(self, canvas: TTkCanvas):
w,h = self.size()
self._screen_current.paintEvent(canvas,w,h)

1403
TermTk/TTkWidgets/TTkTerminal/terminal_alt.py

File diff suppressed because it is too large Load Diff

1429
TermTk/TTkWidgets/TTkTerminal/terminal_normal.py

File diff suppressed because it is too large Load Diff

46
TermTk/TTkWidgets/TTkTerminal/vt102.py

@ -0,0 +1,46 @@
# MIT License
#
# Copyright (c) 2023 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.
from TermTk.TTkCore.color import TTkColor
from TermTk.TTkCore.log import TTkLog
from TermTk.TTkCore.constant import TTkK
from TermTk.TTkCore.cfg import TTkCfg
from TermTk.TTkCore.string import TTkString
from TermTk.TTkCore.signal import pyTTkSignal, pyTTkSlot
from TermTk.TTkCore.helper import TTkHelper
from TermTk.TTkGui.clipboard import TTkClipboard
from TermTk.TTkGui.textwrap1 import TTkTextWrap
from TermTk.TTkGui.textcursor import TTkTextCursor
from TermTk.TTkGui.textdocument import TTkTextDocument
from TermTk.TTkLayouts.gridlayout import TTkGridLayout
from TermTk.TTkAbstract.abstractscrollarea import TTkAbstractScrollArea
from TermTk.TTkAbstract.abstractscrollview import TTkAbstractScrollView, TTkAbstractScrollViewGridLayout
from TermTk.TTkWidgets.widget import TTkWidget
__all__ = ['TTkVT102']
class TTkVT102():
CLEAR = "\033[2J\033[0;0f" # Clear screen and set cursor to position 0,0
ALT_SCREEN = "\033[?1049h" #* Switch to alternate screen
NORMAL_SCREEN = "\033[?1049l" #* Switch to normal screen

2
TermTk/TTkWidgets/__init__.py

@ -28,3 +28,5 @@ from .texedit import TTkTextEdit, TTkTextEditView
from .TTkModelView import *
from .TTkPickers import *
from .window import TTkWindow
from .TTkTerminal import *

3
tests/test.pty.005.fork.py

@ -79,10 +79,11 @@ class TermThread(threading.Thread):
ttk.TTkLog.error(f"Error: {e=}")
return
if o:
# ttk.TTkLog.debug(f'Eugenio->{o}')
ttk.TTkLog.debug(f'Eugenio->{o}')
# self.textEdit.append(o.decode('utf-8').replace('\r','').replace('\033[?2004h','').replace('\033[?2004l',''))
cursor = self.textEdit.textCursor()
cursor.insertText(o.decode('utf-8').replace('\r','').replace('\033[?2004h','').replace('\033[?2004l',''))
# cursor.insertText(o.decode('utf-8').replace('\r','<-r->').replace('\033','<-ESC->'))
cursor.movePosition(ttk.TTkTextCursor.End)
self.textEdit.textEditView()._updateSize()
self.textEdit.textEditView().viewMoveTo(0, cursor.position().line)

66
tests/test.pty.006.terminal.py

@ -0,0 +1,66 @@
#!/usr/bin/env python3
# MIT License
#
# Copyright (c) 2023 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.
# This test is based on:
# pyte - In memory VTXXX-compatible terminal emulator.
# Terminal Emulator Example
# https://github.com/selectel/pyte/blob/master/examples/terminal_emulator.py
#
# pty — Pseudo-terminal utilities¶
# https://docs.python.org/3/library/pty.html#example
#
# Using a pseudo-terminal to interact with interactive Python in a subprocess
# by Thomas Billinger
# https://gist.github.com/thomasballinger/7979808
#
# Run interactive Bash with popen and a dedicated TTY Python
# https://stackoverflow.com/questions/41542960/run-interactive-bash-with-popen-and-a-dedicated-tty-python
import os
import pty
import sys
import threading
from select import select
sys.path.append(os.path.join(sys.path[0],'..'))
import TermTk as ttk
ttk.TTkLog.use_default_file_logging()
root = ttk.TTk()
wlog = ttk.TTkWindow(parent=root,pos = (32,12), size=(90,20), title="Log Window", flags=ttk.TTkK.WindowFlag.WindowCloseButtonHint|ttk.TTkK.WindowFlag.WindowMinMaxButtonsHint)
wlog.setLayout(ttk.TTkHBoxLayout())
ttk.TTkLogViewer(parent=wlog, follow=False )
win1 = ttk.TTkWindow(parent=root, pos=(1,1), size=(70,15), title="Terminallo n.1", border=True, layout=ttk.TTkVBoxLayout(), flags = ttk.TTkK.WindowFlag.WindowMinMaxButtonsHint)
term1 = ttk.TTkTerminal(parent=win1)
term1.runShell()
win2 = ttk.TTkWindow(parent=root, pos=(10,5), size=(70,15), title="Terminallo n.2", border=True, layout=ttk.TTkVBoxLayout(), flags = ttk.TTkK.WindowFlag.WindowMinMaxButtonsHint)
term2 = ttk.TTkTerminal(parent=win2)
term2.runShell()
root.mainloop()

224
tests/timeit/15.strings.01.re.loop.py

@ -0,0 +1,224 @@
#!/usr/bin/env python3
# MIT License
#
# Copyright (c) 2023 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.
import sys, os
import timeit
import re
sys.path.append(os.path.join(sys.path[0],'../..'))
# Testing a string contain different kind of matches
# Uppercase the matching pattern
# With the one mimic the VT100 escape codes "A...x"
testString1 = (
"123456Aabcdef01" + "A[123A" +
"123456Babcdef02" + "A[123B" +
"123456Babcdef03" + "A[12C" +
"123456Babcdef04" + "A[1D" +
"123456Babcdef05" + "A[?123l" +
"123456Babcdef06" + "A[?123h" +
"123456Babcdef07" + "A[?4l" +
"123456Babcdef08" + "A[?5h" +
"123456Babcdef09" + "A[1E" +
"123456Cabcdef10" + "A[1;3H" +
"123456Cabcdef11" + "A[;f" +
"123456Dabcdef12" + "A[123F" +
"123456Eabcdef13" + "A[12;34f" )
testString2 = (
"123456Aabcdef01" + "A[123A" +
"123456Cabcdef10" + "A[1;3H" +
"123456Eabcdef13" )
testString3 = (
"123456Aabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdef01" + "A[123A" +
"123456Eabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdef13" )
re_P1_1 = re.compile(r'^(\d*);(\d*)([Hf])')
re_P1_2 = re.compile(r'^\?(\d+)([lh])')
re_P1_3 = re.compile(r'^(\d+)([ABCDEFGIJKLMPSTXZ])')
def process1_1(txt):
_lines = []
_cursor = (1,1)
lines = txt.split('A')
for i,l in enumerate(lines):
if i:
_lines.append("")
_cursor = (0,len(_lines)-1)
ls = l.split('B')
for ii,ll in enumerate(ls):
if ii:
_cursor = (0,len(_lines)-1)
lls = ll.split('C')
for iii,lll in enumerate(lls):
if iii:
x,y = _cursor
_cursor = (max(0,x-1),y)
_lines.append(lll)
return len(lines) +_cursor[0] + _cursor[1]
def process1(txt):
r = 0
tmp = []
sout = txt.split('A[')
r += process1_1(sout[0])
for slice in sout[1:]:
if m := re_P1_2.match(slice):
l = len(m.group(0))
ps = int(m.group(1))
sr = m.group(2)
tmp.append((ps,sr))
slice = slice[l:]
elif m := re_P1_1.match(slice):
l = len(m.group(0))
y = m.group(1)
x = m.group(2)
tp = m.group(3)
tmp.append((y,x,tp))
slice = slice[l:]
elif m := re_P1_3.match(slice):
l = len(m.group(0))
ps = int(m.group(1))
sr = m.group(2)
tmp.append((ps,sr))
slice = slice[l:]
else:
slice = '\033[' + slice.replace('\r','')
r += process1_1(slice)
return r + len(tmp)
re_P2_1 = re.compile(r'A\[(\d*);(\d*)([Hf])')
re_P2_2 = re.compile(r'A\[\?(\d+)([lh])')
re_P2_3 = re.compile(r'A\[(\d+)([ABCDEFGIJKLMPSTXZ])')
re_P2_4 = re.compile(r'[ABCD]')
def process2_2(txt):
ret=0
pos = 0
prev = 0
lll = len(txt)
x,y = 0,0
xxx = {
"A":lambda :(x+1,y),
"B":lambda :(x-1,y),
"C":lambda :(x,y+1),
"D":lambda :(x,y-1),
}
while pos < lll:
if m := re_P2_4.search(txt,pos):
gr = m.group()
ln = 1
st = m.start()
en = pos = st+1
_x = xxx.get(gr,lambda :(x,y))
x,y = _x()
ret += x+y
ret += len(txt[prev:st])
prev = en
else:
ret += len(txt[prev:])
break
return ret
def process2_1(txt):
ret=0
pos = 0
prev = 0
lll = len(txt)
while pos < lll:
if m := re_P2_1.search(txt,pos):
gr = m.group()
ln = len(gr)
st = m.start()
en = pos = m.end()
y = int(vv) if (vv:=m.group(1)) else 0
x = int(vv) if (vv:=m.group(2)) else 0
ty = m.group(3)
ret += x+y
ret += process2_2(txt[prev:st])
prev = en
elif m := re_P2_3.search(txt,pos):
gr = m.group()
ln = len(gr)
st = m.start()
ps = int(m.group(1))
sr = m.group(2)
en = pos = m.end()
ret += ps
ret += process2_2(txt[prev:st])
prev = en
else:
ret += process2_2(txt[prev:])
break
return ret
def process2(txt):
ret=0
pos = 0
prev = 0
lll = len(txt)
xxx = {
"A[123l":lambda x:len(x)+1,
"A[123l":lambda x:len(x)+2,
}
while pos < lll:
if m := re_P2_2.search(txt,pos):
gr = m.group()
ln = len(gr)
st = m.start()
en = pos = m.end()
_x = xxx.get(gr,lambda x:len(x)+3)
ret += _x(txt[st:en])
ret += process2_1(txt[prev:st])
prev = en
else:
ret += process2_1(txt[prev:])
break
return ret
def test1(): return process1(testString1)
def test2(): return process1(testString2)
def test3(): return process1(testString3)
def test4(): return process2(testString1)
def test5(): return process2(testString2)
def test6(): return process2(testString3)
def test7(): return 7
def test8(): return 8
def test9(): return 9
loop = 10000
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

94
tests/timeit/15.strings.02.re.py

@ -0,0 +1,94 @@
#!/usr/bin/env python3
# MIT License
#
# Copyright (c) 2023 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.
import sys, os
import timeit
import re
sys.path.append(os.path.join(sys.path[0],'../..'))
# Testing a string contain different kind of matches
# Uppercase the matching pattern
# With the one mimic the VT100 escape codes "A...x"
testString1 = "A[12;3H" + "abc"
testString2 = "A[123A" + "abc"
testString3 = "A[;f" + "abc"
# xterm escape sequences from:
# https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
# https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_
re_CURSOR = re.compile('^A\[(\d*);?(\d*)([ABCDEFGIJKLMPSTXZHf@])')
# https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_
# Basic Re for CSI Ps matches:
# CSI : Control Sequence Introducer "<ESC>[" = '\033['
# Ps : A single (usually optional) numeric parameter, composed of one or more digits.
# fu : the single char defining the function
re_CSI_Ps_fu = re.compile('^A\[(\d*)([ABCDEFGIJKLMPSTXZ@])')
re_CSI_Ps_Ps_fu = re.compile('^A\[(\d*);(\d*)([Hf])')
re_CSI_Mix = re.compile('^A\[(\d*)([ABCDEFGIJKLMPSTXZ@])|A\[(\d*);(\d*)([Hf])')
re_DEC_SET_RST = re.compile('A\[\?(\d+)([lh])')
# re_CURSOR_1 = re.compile(r'^(\d+)([ABCDEFGIJKLMPSTXZHf])')
def process1(txt):
if m:=re_CURSOR.match(txt):
return 1
return 3
def process2(txt):
if m:=re_CSI_Ps_fu.match(txt):
return 1
elif m:=re_CSI_Ps_Ps_fu.match(txt):
return 2
return 3
def process3(txt):
if m:=re_CSI_Mix.match(txt):
return 1
return 3
def test1(): return process1(testString1)
def test2(): return process1(testString2)
def test3(): return process1(testString3)
def test4(): return process2(testString1)
def test5(): return process2(testString2)
def test6(): return process2(testString3)
def test7(): return process3(testString1)
def test8(): return process3(testString2)
def test9(): return process3(testString3)
loop = 100000
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

151
tests/timeit/16.dict.01.get.py

@ -0,0 +1,151 @@
#!/usr/bin/env python3
# MIT License
#
# Copyright (c) 2023 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.
import sys, os
import timeit
sys.path.append(os.path.join(sys.path[0],'../..'))
D1 = {
'a' : lambda x, _ : 2*x,
'b' : lambda x, _ : 2*x,
'c' : lambda x, _ : 2*x,
'd' : lambda x, _ : 2*x,
'e' : lambda x, _ : 2*x,
'f' : lambda x, _ : 2*x,
'g' : lambda x, _ : 2*x,
'h' : lambda x, _ : 2*x,
'i' : lambda x, _ : 2*x,
'j' : lambda x, _ : 2*x,
'k' : lambda x, _ : 2*x,
'l' : lambda x, y : 2*x+y,
'm' : lambda x, _ : 2*x,
'n' : lambda x, _ : 2*x,
'o' : lambda x, _ : 2*x,
'p' : lambda x, y : 2*x+y,
'q' : lambda x, _ : 2*x,
'r' : lambda x, _ : 2*x,
's' : lambda x, y : 2*x+y,
't' : lambda x, _ : 2*x,
'u' : lambda x, y : 2*x+y,
'v' : lambda x, _ : 2*x,
'w' : lambda x, _ : 2*x,
'x' : lambda x, _ : 2*x,
'y' : lambda x, _ : 2*x,
'z' : lambda x, _ : 2*x,
}
D2_1 = {
'a' : lambda x: 2*x,
'b' : lambda x: 2*x,
'c' : lambda x: 2*x,
'd' : lambda x: 2*x,
'e' : lambda x: 2*x,
'f' : lambda x: 2*x,
'g' : lambda x: 2*x,
'h' : lambda x: 2*x,
'i' : lambda x: 2*x,
'j' : lambda x: 2*x,
'k' : lambda x: 2*x,
'm' : lambda x: 2*x,
'n' : lambda x: 2*x,
'o' : lambda x: 2*x,
'q' : lambda x: 2*x,
'r' : lambda x: 2*x,
't' : lambda x: 2*x,
'v' : lambda x: 2*x,
'w' : lambda x: 2*x,
'x' : lambda x: 2*x,
'y' : lambda x: 2*x,
'z' : lambda x: 2*x,
}
D2_2 = {
'l' : lambda x, y : 2*x+y,
'p' : lambda x, y : 2*x+y,
's' : lambda x, y : 2*x+y,
'u' : lambda x, y : 2*x+y,
}
test_input_1 = {
'a' : (2,None),
'b' : (2,None),
'c' : (2,None),
'd' : (2,None),
'e' : (2,None),
'l' : (2,2),
'p' : (2,2),
's' : (2,2),
'n' : (2,None),
'o' : (2,None),
'z' : (2,None),
'y' : (2,None),
'u' : (2,2),
}
def process1(ttt):
ret = 0
for i in ttt:
x,y = ttt[i]
_v = D1.get(i,lambda x,y:None)
ret += _v(x,y)
return ret
def process2(ttt):
ret = 0
for i in ttt:
x,y = ttt[i]
if y:
_v = D2_2.get(i,lambda x,y:None)
ret += _v(x,y)
else:
_v = D2_1.get(i,lambda x:None)
ret += _v(x)
return ret
def process3(ttt):
return 3
def test1(): return process1(test_input_1)
def test2(): return process1(test_input_1)
def test3(): return process1(test_input_1)
def test4(): return process2(test_input_1)
def test5(): return process2(test_input_1)
def test6(): return process2(test_input_1)
def test7(): return process3(test_input_1)
def test8(): return process3(test_input_1)
def test9(): return process3(test_input_1)
loop = 100000
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
Loading…
Cancel
Save