[python-meh] Allow a change of the I/O functions

Vratislav Podzimek vpodzime at redhat.com
Tue Mar 26 13:56:59 UTC 2013


This is needed for Anaconda's text mode that has its own raw_input
function that has to be used also by python-meh. And it will come
handy when writing automated tests for python-meh's text interface.

Signed-off-by: Vratislav Podzimek <vpodzime at redhat.com>
---
 meh/ui/text.py | 79 ++++++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 63 insertions(+), 16 deletions(-)

diff --git a/meh/ui/text.py b/meh/ui/text.py
index 1b1e297..9bed60a 100644
--- a/meh/ui/text.py
+++ b/meh/ui/text.py
@@ -17,6 +17,8 @@
 # Author(s): Chris Lumens <clumens at redhat.com>
 #            Vratislav Podzimek <vpodzime at redhat.com>
 #
+from __future__ import print_function
+
 from meh import *
 from meh.ui import *
 import report
@@ -28,10 +30,40 @@ import os
 import gettext
 _ = lambda x: gettext.ldgettext("python-meh", x)
 
+
+class IOHandler(object):
+    """
+    Class that provides methods for input and output. Its instance is expected
+    to be passed to objects performing some I/O operations.
+
+    """
+
+    def __init__(self, in_func=raw_input, out_func=print):
+        """
+        Constructor for the IOhandler class. Arguments can be used to override
+        default I/O functions with the custom ones.
+
+        @param in_func: input function similar to standard raw_input
+        @type in_func: str -> str
+        @param out_func: output function similar to standard print
+        @type out_func: str -> None
+
+        """
+
+        self.in_func = in_func
+        self.out_func = out_func
+
+    def print(self, msg=""):
+        self.out_func(msg)
+
+    def raw_input(self, prompt):
+        return self.in_func(prompt)
+
 class TextWindow(object):
     """Helper class providing some common methods needed by all text windows."""
 
     def __init__(self, title, *args, **kwargs):
+        self._io = kwargs.get("io_handler", IOHandler())
         self._title = title
 
         # XXX: I know this must be really hard for translators, but there is no
@@ -45,12 +77,12 @@ class TextWindow(object):
 
     def _print_rule(self):
         rule = self._usable_width * "="
-        print rule
+        self._io.print(rule)
 
     def print_header(self):
-        print
+        self._io.print()
         self._print_rule()
-        print self._title
+        self._io.print(self._title)
         self._print_rule()
 
     def destroy(self):
@@ -61,6 +93,16 @@ class TextIntf(AbstractIntf):
     def __init__(self, *args, **kwargs):
         AbstractIntf.__init__(self, *args, **kwargs)
         self.screen = kwargs.get("screen", None)
+        self._io = kwargs.get("io_handler", IOHandler())
+
+    def set_io_handler(self, handler):
+        """
+        Set different IO handler.
+
+        @type handler: an instance of the IOHandler class
+
+        """
+        self._io = handler
 
     def enableNetwork(self, *args, **kwargs):
         """Should be provided by the inheriting class."""
@@ -68,20 +110,24 @@ class TextIntf(AbstractIntf):
         return False
 
     def exitWindow(self, title, message, *args, **kwargs):
+        kwargs["io_handler"] = self._io
         win = ExitWindow(title, message, *args, **kwargs)
         win.run()
         win.destroy()
 
     def mainExceptionWindow(self, text, exnFile, *args, **kwargs):
+        kwargs["io_handler"] = self._io
         win = MainExceptionWindow(text, exnFile, *args, **kwargs)
         return win
 
     def messageWindow(self, title, message, *args, **kwargs):
+        kwargs["io_handler"] = self._io
         win = MessageWindow(title, message, *args, **kwargs)
         win.run()
         win.destroy()
 
     def saveExceptionWindow(self, signature, *args, **kwargs):
+        kwargs["io_handler"] = self._io
         win = SaveExceptionWindow(signature, *args, **kwargs)
         win.run()
         win.destroy()
@@ -112,16 +158,16 @@ class MainExceptionWindow(TextWindow, AbstractMainExceptionWindow):
 
     def run(self, *args, **kwargs):
         self.print_header()
-        print self._short_traceback
-        print _("What do you want to do now?")
+        self._io.print(self._short_traceback)
+        self._io.print(_("What do you want to do now?"))
         for (idx, item) in enumerate(self._menu_items):
-            print "%d) %s" % (idx + 1, item[0])
+            self._io.print("%d) %s" % (idx + 1, item[0]))
 
         ret = -1
         num_menu_items = len(self._menu_items)
-        print
+        self._io.print()
         while not (0 < ret <= num_menu_items):
-            ret = raw_input(_("Please make your choice from above: "))
+            ret = self._io.raw_input(_("Please make your choice from above: "))
             try:
                 ret = int(ret)
             except ValueError:
@@ -137,9 +183,9 @@ class MessageWindow(TextWindow, AbstractMessageWindow):
 
     def run(self, *args, **kwargs):
         self.print_header()
-        print self._text
-        print
-        raw_input(_("Hit ENTER to continue"))
+        self._io.print(self._text)
+        self._io.print()
+        self._io.raw_input(_("Hit ENTER to continue"))
 
 class ExitWindow(MessageWindow):
     def __init__(self, title, text, *args, **kwargs):
@@ -147,14 +193,15 @@ class ExitWindow(MessageWindow):
 
     def run(self, *args, **kwargs):
         self.print_header()
-        print self._text
-        print
+        self._io.print(self._text)
+        self._io.print()
 
         # self._no_answer may be non-ascii string (simple .upper() doesn't work)
         no_answer_upper = self._no_answer.decode("utf-8").upper().encode("utf-8")
-        answer = raw_input(_("Are you sure you want to exit? [%(yes)s/%(no)s]") %
-                           { "yes": self._yes_answer,
-                             "no": no_answer_upper })
+        answer = self._io.raw_input(_(
+                          "Are you sure you want to exit? [%(yes)s/%(no)s]") %
+                                    { "yes": self._yes_answer,
+                                      "no": no_answer_upper })
 
         # no answer means accepting the default (self._no_answer) and the answer
         # is case insensitive (and may be non-ascii)
-- 
1.7.11.7



More information about the anaconda-patches mailing list