dexter has uploaded this change for review. ( 
https://gerrit.osmocom.org/c/pysim/+/41229?usp=email )


Change subject: pySim-shell: set callback function to print formatted warnings
......................................................................

pySim-shell: set callback function to print formatted warnings

In many sub modules we still use print() to occassionally print status
messages or warnings. This technically does not hurt, but it is an unclean
solution which we should replace with something more mature.

The python provided warnings module provides a warn() function that can
be used to send warnings to higher layers. The higher layers can receive
the warnings via a callback and then decide what to do with it. In our
application we will format and print the warnings using the cmd2 provided
functions (or print in case the cmd2 object does not exist yet.)

Let's also add a custom warning class "Info", which we can use to print
informative messages

To illustrate how the approach can be used in sub-modules, this also
replaces the print() calls in runtimpe.py with warn() calls.

Related: OS#6864
Change-Id: I187f117e7e1ccdb2a85dfdfb18e84bd7561704eb
---
M pySim-shell.py
M pySim/runtime.py
A pySim/warnings.py
3 files changed, 56 insertions(+), 6 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/29/41229/1

diff --git a/pySim-shell.py b/pySim-shell.py
index 977666c..6b81628 100755
--- a/pySim-shell.py
+++ b/pySim-shell.py
@@ -24,17 +24,20 @@
 import re

 import cmd2
+import warnings
 from packaging import version
 from cmd2 import style
 # cmd2 >= 2.3.0 has deprecated the bg/fg in favor of Bg/Fg :(
 if version.parse(cmd2.__version__) < version.parse("2.3.0"):
     from cmd2 import fg, bg # pylint: disable=no-name-in-module
     RED = fg.red
+    YELLOW = fg.yellow
     LIGHT_RED = fg.bright_red
     LIGHT_GREEN = fg.bright_green
 else:
     from cmd2 import Fg, Bg # pylint: disable=no-name-in-module
     RED = Fg.RED
+    YELLOW = Fg.YELLOW
     LIGHT_RED = Fg.LIGHT_RED
     LIGHT_GREEN = Fg.LIGHT_GREEN
 from cmd2 import CommandSet, with_default_category, with_argparser
@@ -67,6 +70,15 @@

 from pySim.app import init_card

+def __format_warning(message, category, filename, lineno, debug=False):
+    if category.__name__ == "Info":
+        color = None
+    else:
+        color = YELLOW
+    if debug == True:
+        return style("%s: %s, in file: %s:%s" % (category.__name__, message, 
filename, lineno), fg=color)
+    else:
+        return style("%s: %s" % (category.__name__, message), fg=color)

 class Cmd2Compat(cmd2.Cmd):
     """Backwards-compatibility wrapper around cmd2.Cmd to support older and 
newer
@@ -92,6 +104,9 @@
 (C) 2021-2023 by Harald Welte, sysmocom - s.f.m.c. GmbH and contributors
 Online manual available at 
https://downloads.osmocom.org/docs/pysim/master/html/shell.html """

+    def __print_warning(self, message, category, filename, lineno, file=None, 
line=None):
+        self.poutput(__format_warning(message, category, filename, lineno, 
self.debug))
+
     def __init__(self, card, rs, sl, ch, script=None):
         if version.parse(cmd2.__version__) < version.parse("2.0.0"):
             kwargs = {'use_ipython': True}
@@ -101,6 +116,7 @@
         # pylint: disable=unexpected-keyword-arg
         super().__init__(persistent_history_file='~/.pysim_shell_history', 
allow_cli_args=False,
                          auto_load_commands=False, startup_script=script, 
**kwargs)
+        warnings.showwarning = self.__print_warning
         self.intro = style(self.BANNER, fg=RED)
         self.default_category = 'pySim-shell built-in commands'
         self.card = None
@@ -1098,6 +1114,12 @@

 if __name__ == '__main__':

+    # Ensure that we are able to print formatted warnings from the beginning. 
When the PysimApp is created, this
+    # this callback will be replaced with a different callback (see above)
+    def __print_warning(message, category, filename, lineno, file=None, 
line=None):
+        print(__format_warning(message, category, filename, lineno))
+    warnings.showwarning = __print_warning
+
     startup_errors = False
     opts = option_parser.parse_args()

diff --git a/pySim/runtime.py b/pySim/runtime.py
index 5bb730e..f47c053 100644
--- a/pySim/runtime.py
+++ b/pySim/runtime.py
@@ -17,11 +17,13 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.

+from warnings import warn
 from typing import Optional, Tuple
 from osmocom.utils import h2b, i2h, is_hex, Hexstr
 from osmocom.tlv import bertlv_parse_one

 from pySim.exceptions import *
+from pySim.warnings import Info
 from pySim.filesystem import *

 def lchan_nr_from_cla(cla: int) -> int:
@@ -66,7 +68,7 @@
         for addon_cls in self.profile.addons:
             addon = addon_cls()
             if addon.probe(self.card):
-                print("Detected %s Add-on \"%s\"" % (self.profile, addon))
+                warn("Detected %s Add-on \"%s\"" % (self.profile, addon), Info)
                 for f in addon.files_in_mf:
                     self.mf.add_file(f)

@@ -100,18 +102,18 @@
         apps_taken = []
         if aids_card:
             aids_taken = []
-            print("AIDs on card:")
+            warn("AIDs on card:", Info)
             for a in aids_card:
                 for f in apps_profile:
                     if f.aid in a:
-                        print(" %s: %s (EF.DIR)" % (f.name, a))
+                        warn(" %s: %s (EF.DIR)" % (f.name, a), Info)
                         aids_taken.append(a)
                         apps_taken.append(f)
             aids_unknown = set(aids_card) - set(aids_taken)
             for a in aids_unknown:
-                print(" unknown: %s (EF.DIR)" % a)
+                warn(" unknown: %s (EF.DIR)" % a, Info)
         else:
-            print("warning: EF.DIR seems to be empty!")
+            warn("EF.DIR seems to be empty!", Warning)

         # Some card applications may not be registered in EF.DIR, we will 
actively
         # probe for those applications
@@ -126,7 +128,7 @@
                 _data, sw = self.card.select_adf_by_aid(f.aid)
                 self.selected_adf = f
                 if sw == "9000":
-                    print(" %s: %s" % (f.name, f.aid))
+                    warn(" %s: %s" % (f.name, f.aid), Info)
                     apps_taken.append(f)
             except (SwMatchError, ProtocolError):
                 pass
diff --git a/pySim/warnings.py b/pySim/warnings.py
new file mode 100644
index 0000000..628fb81
--- /dev/null
+++ b/pySim/warnings.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+
+""" pySim: Warnings
+"""
+
+#
+# (C) 2024 by Sysmocom s.f.m.c. GmbH
+# All Rights Reserved
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+class Info(Warning):
+    """Informative message, technically not a warning."""
+

--
To view, visit https://gerrit.osmocom.org/c/pysim/+/41229?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings?usp=email

Gerrit-MessageType: newchange
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I187f117e7e1ccdb2a85dfdfb18e84bd7561704eb
Gerrit-Change-Number: 41229
Gerrit-PatchSet: 1
Gerrit-Owner: dexter <[email protected]>

Reply via email to