From b51301533c341817201d2dbd7b9cda6bf7f299fe Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Thu, 18 Feb 2021 12:09:16 +0000 Subject: [PATCH] Reworked the log helper --- README.md | 2 +- {ttk => TermTk/TTk}/__init__.py | 0 TermTk/TTk/log.py | 86 +++++++++++++++++++++++++++ TermTk/__init__.py | 0 {ttk => TermTk}/libbpytop/LICENSE | 0 {ttk => TermTk}/libbpytop/README.md | 0 {ttk => TermTk}/libbpytop/__init__.py | 0 TermTk/libbpytop/canvas..py | 16 +++++ {ttk => TermTk}/libbpytop/input.py | 6 +- {ttk => TermTk}/libbpytop/term.py | 15 +++++ docs/TODO.md | 13 +++- tests/test.input.py | 31 +++++----- ttk/log.py | 72 ---------------------- 13 files changed, 149 insertions(+), 92 deletions(-) rename {ttk => TermTk/TTk}/__init__.py (100%) create mode 100644 TermTk/TTk/log.py create mode 100644 TermTk/__init__.py rename {ttk => TermTk}/libbpytop/LICENSE (100%) rename {ttk => TermTk}/libbpytop/README.md (100%) rename {ttk => TermTk}/libbpytop/__init__.py (100%) create mode 100644 TermTk/libbpytop/canvas..py rename {ttk => TermTk}/libbpytop/input.py (97%) rename {ttk => TermTk}/libbpytop/term.py (88%) delete mode 100644 ttk/log.py diff --git a/README.md b/README.md index dbb1b32b..2f751ef8 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ -# py-ttk +# pyTermTk Python Terminal Toolkit diff --git a/ttk/__init__.py b/TermTk/TTk/__init__.py similarity index 100% rename from ttk/__init__.py rename to TermTk/TTk/__init__.py diff --git a/TermTk/TTk/log.py b/TermTk/TTk/log.py new file mode 100644 index 00000000..79147d67 --- /dev/null +++ b/TermTk/TTk/log.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 + +# MIT License +# +# Copyright (c) 2021 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. + +# This code is inspired by +# https://github.com/ceccopierangiolieugenio/pyCuT/blob/master/cupy/CuTCore/CuDebug.py + +import inspect +from collections.abc import Callable + +class _TTkContext: + __slots__ = ['file', 'line', 'function'] + def __init__(self, cf): + self.file = cf[1] + self.line = cf[2] + self.function = cf[3] + def __str__(self): + return f"{self.file}:{self.line} [{self.function}]" + +class TTkLog: + DebugMsg = 0x0001 + InfoMsg = 0x0002 + ErrorMsg = 0x0004 + WarningMsg = 0x0008 + CriticalMsg = 0x0010 + FatalMsg = 0x0020 + SystemMsg = CriticalMsg + + _messageHandler: Callable = None + + @staticmethod + def _process_msg(mode: int, msg: str): + if TTkLog._messageHandler is not None: + curframe = inspect.currentframe() + calframe = inspect.getouterframes(curframe,1) + if len(calframe) > 2: + ctx = _TTkContext(calframe[2]) + TTkLog._messageHandler(mode, ctx, msg) + + @staticmethod + def debug(msg): + TTkLog._process_msg(TTkLog.DebugMsg, msg) + + @staticmethod + def info(msg): + TTkLog._process_msg(TTkLog.InfoMsg, msg) + + @staticmethod + def error(msg): + TTkLog._process_msg(TTkLog.ErrorMsg, msg) + + @staticmethod + def warn(msg): + TTkLog._process_msg(TTkLog.WarningMsg, msg) + + @staticmethod + def critical(msg): + TTkLog._process_msg(TTkLog.CriticalMsg, msg) + + @staticmethod + def fatal(msg): + TTkLog._process_msg(TTkLog.FatalMsg, msg) + + @staticmethod + def installMessageHandler(mh: Callable): + TTkLog._messageHandler = mh \ No newline at end of file diff --git a/TermTk/__init__.py b/TermTk/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ttk/libbpytop/LICENSE b/TermTk/libbpytop/LICENSE similarity index 100% rename from ttk/libbpytop/LICENSE rename to TermTk/libbpytop/LICENSE diff --git a/ttk/libbpytop/README.md b/TermTk/libbpytop/README.md similarity index 100% rename from ttk/libbpytop/README.md rename to TermTk/libbpytop/README.md diff --git a/ttk/libbpytop/__init__.py b/TermTk/libbpytop/__init__.py similarity index 100% rename from ttk/libbpytop/__init__.py rename to TermTk/libbpytop/__init__.py diff --git a/TermTk/libbpytop/canvas..py b/TermTk/libbpytop/canvas..py new file mode 100644 index 00000000..0033ce0a --- /dev/null +++ b/TermTk/libbpytop/canvas..py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 + +# Copyright 2021 Eugenio Parodi +# Copyright 2020 Aristocratos (https://github.com/aristocratos/bpytop) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. \ No newline at end of file diff --git a/ttk/libbpytop/input.py b/TermTk/libbpytop/input.py similarity index 97% rename from ttk/libbpytop/input.py rename to TermTk/libbpytop/input.py index 3538692a..aa244af3 100644 --- a/ttk/libbpytop/input.py +++ b/TermTk/libbpytop/input.py @@ -27,6 +27,8 @@ except Exception as e: print(f'ERROR: {e}') exit(1) +from TermTk.TTk import TTkLog + class MouseEvent: # Keys NoButton = 0x00000000 # The button state does not refer to any button (see QMouseEvent::button()). @@ -138,6 +140,7 @@ class Input: m = mouse_re.match(input_key) if not m: # TODO: Return Error + TTkLog.error("UNHANDLED: "+input_key.replace("\033","")) continue code = int(m.group(1)) x = int(m.group(2)) @@ -170,7 +173,8 @@ class Input: key = MouseEvent.Wheel evt = MouseEvent.Down mevt = MouseEvent(x, y, key, evt, m.group(0).replace("\033", "")) - + else: + TTkLog.error("UNHANDLED: "+input_key.replace("\033","")) input_key = "" if callback is not None: callback(kevt, mevt) diff --git a/ttk/libbpytop/term.py b/TermTk/libbpytop/term.py similarity index 88% rename from ttk/libbpytop/term.py rename to TermTk/libbpytop/term.py index 5ad60db3..4bf389e3 100644 --- a/ttk/libbpytop/term.py +++ b/TermTk/libbpytop/term.py @@ -44,6 +44,19 @@ class Term: _sigWinChCb = None + @staticmethod + def init(mouse: bool = True, title: str = "TermTk"): + Term.push(Term.alt_screen, Term.clear, Term.hide_cursor, Term.title("BpyTOP")) + if mouse: + Term.push(Term.mouse_on) + Term.echo(False) + + @staticmethod + def exit(): + Term.push(Term.mouse_off, Term.mouse_direct_off) + Term.echo(True) + + @staticmethod def echo(on: bool): """Toggle input echo""" @@ -79,5 +92,7 @@ class Term: @staticmethod def registerResizeCb(callback): Term._sigWinChCb = callback + # Dummy call to retrieve the terminal size + Term._sigWinCh(signal.SIGWINCH, None) signal.signal(signal.SIGWINCH, Term._sigWinCh) diff --git a/docs/TODO.md b/docs/TODO.md index 191e65b8..e3fe4318 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -1,15 +1,22 @@ -- [ ] Handle Logs +# TODO +- [ ] Follow [PEP 8](https://www.python.org/dev/peps/pep-0008/) coding style - [ ] Terminal Helper - [ ] Events - [x] Window : SIGWINCH triggered when the terminal is resized - [ ] Input Class - [ ] Return Error if Mouse RE does not match - [x] Handle the Paste Buffer - - [ ] Handle the middle button mouse paste + - [ ] Investigate the middle mouse button paste + *note: It works only in "INSERT" mode on Vim* - [ ] Handle Special Keys (UP, Down, . . .) - [ ] Events https://tkinterexamples.com/events/events.html https://www.pythontutorial.net/tkinter/tkinter-event-binding/ - [x] Keyboard - [x] Mouse -- [ ] Canvas Class \ No newline at end of file +- [ ] Canvas Class +- [ ] Logs + - [x] Log Class + - [ ] Log helpers + - [ ] logger auto integration + - [ ] stdout until mainLoop \ No newline at end of file diff --git a/tests/test.input.py b/tests/test.input.py index 7540b858..61064aa9 100644 --- a/tests/test.input.py +++ b/tests/test.input.py @@ -2,35 +2,36 @@ import sys, os import logging sys.path.append(os.path.join(sys.path[0],'..')) -import ttk.libbpytop as lbt -import ttk +import TermTk.libbpytop as lbt +from TermTk.TTk import TTkLog def message_handler(mode, context, message): - if mode == ttk.InfoMsg: mode = 'INFO' - elif mode == ttk.WarningMsg: mode = 'WARNING' - elif mode == ttk.CriticalMsg: mode = 'CRITICAL' - elif mode == ttk.FatalMsg: mode = 'FATAL' - else: mode = 'DEBUG' - logging.debug(f"{mode} {context.file} {message}") + log = logging.debug + if mode == TTkLog.InfoMsg: log = logging.info + elif mode == TTkLog.WarningMsg: log = logging.warning + elif mode == TTkLog.CriticalMsg: log = logging.critical + elif mode == TTkLog.FatalMsg: log = logging.fatal + elif mode == TTkLog.ErrorMsg: log = logging.error + log(f"{context.file} {message}") logging.basicConfig(level=logging.DEBUG, - format='(%(threadName)-9s) %(message)s',) -ttk.installMessageHandler(message_handler) + format='%(levelname)s:(%(threadName)-9s) %(message)s',) +TTkLog.installMessageHandler(message_handler) -ttk.info("Retrieve Keyboard, Mouse press/drag/wheel Events") -ttk.info("Press q or to exit") +TTkLog.info("Retrieve Keyboard, Mouse press/drag/wheel Events") +TTkLog.info("Press q or to exit") lbt.Term.push(lbt.Term.mouse_on) lbt.Term.echo(False) def keyCallback(kevt=None, mevt=None): if kevt is not None: - ttk.info(f"Key Event: {kevt}") + TTkLog.info(f"Key Event: {kevt}") if mevt is not None: - ttk.info(f"Mouse Event: {mevt}") + TTkLog.info(f"Mouse Event: {mevt}") def winCallback(width, height): - ttk.info(f"Resize: w:{width}, h:{height}") + TTkLog.info(f"Resize: w:{width}, h:{height}") lbt.Term.registerResizeCb(winCallback) lbt.Input.get_key(keyCallback) diff --git a/ttk/log.py b/ttk/log.py deleted file mode 100644 index 49dc260d..00000000 --- a/ttk/log.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python3 - -# MIT License -# -# Copyright (c) 2021 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. - -# This code is inspired by -# https://github.com/ceccopierangiolieugenio/pyCuT/blob/master/cupy/CuTCore/CuDebug.py - -import inspect - -DebugMsg = 0 # A message generated by the Debug() function. -InfoMsg = 4 # A message generated by the Info() function. -WarningMsg = 1 # A message generated by the Warning() function. -CriticalMsg = 2 # A message generated by the Critical() function. -FatalMsg = 3 # A message generated by the Fatal() function. -SystemMsg = CriticalMsg - -_MessageHandler = None - -def _process_msg(mode, msg): - global _MessageHandler - if _MessageHandler is not None: - curframe = inspect.currentframe() - calframe = inspect.getouterframes(curframe,1) - if len(calframe) > 2: - class context: - __slots__ = ('file', 'line', 'function') - def __str__(self): - return f"{self.file}:{self.line} [{self.function}]" - ctx = context() - ctx.file = calframe[2][1] - ctx.line = calframe[2][2] - ctx.function = calframe[2][3] - _MessageHandler(mode, ctx, msg) - -def debug(msg): - _process_msg(DebugMsg, msg) - -def info(msg): - _process_msg(InfoMsg, msg) - -def warn(msg): - _process_msg(WarningMsg, msg) - -def critical(msg): - _process_msg(CriticalMsg, msg) - -def fatal(msg): - _process_msg(FatalMsg, msg) - -def installMessageHandler(mh): - global _MessageHandler - _MessageHandler = mh \ No newline at end of file