-
Notifications
You must be signed in to change notification settings - Fork 15
/
text.py
235 lines (187 loc) · 8.18 KB
/
text.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
# Copyright (C) 2009, 2013 Red Hat, Inc.
# 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/>.
#
# Author(s): Chris Lumens <[email protected]>
# Vratislav Podzimek <[email protected]>
#
from __future__ import print_function
from meh import MAIN_RESPONSE_DEBUG, MAIN_RESPONSE_SAVE, MAIN_RESPONSE_SHELL, MAIN_RESPONSE_QUIT
from meh.ui import AbstractIntf, AbstractSaveExceptionWindow, AbstractMainExceptionWindow, AbstractMessageWindow
LIBREPORT_AVAILABLE = False
try:
import report
import report.io.TextIO
from report import LIBREPORT_WAIT, LIBREPORT_RUN_CLI
LIBREPORT_AVAILABLE = True
except ImportError:
print("libreport is not available in this environment - bug reporting disabled")
import os
import sys
if sys.version_info.major == 3:
raw_input_fn = input
else:
raw_input_fn = raw_input # pylint: disable=undefined-variable
import gettext
_ = lambda x: gettext.translation("python-meh", fallback=True).gettext(x) if x != "" else ""
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_fn, out_func=print): # pylint: disable=used-before-assignment
"""
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
# short (one-char) answer meaning "yes"
self._yes_answer = _("y")
# short (one-char) answer meaning "no"
self._no_answer = _("n")
@property
def _usable_width(self):
return os.environ.get("COLUMNS", 80) - 1
def _print_rule(self):
rule = self._usable_width * "="
self._io.print(rule)
def print_header(self):
self._io.print()
self._print_rule()
self._io.print(self._title)
self._print_rule()
def destroy(self):
self._print_rule()
self._print_rule()
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."""
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()
class SaveExceptionWindow(TextWindow, AbstractSaveExceptionWindow):
def __init__(self, signature, *args, **kwargs):
AbstractSaveExceptionWindow.__init__(self, signature,
*args, **kwargs)
TextWindow.__init__(self, _("Save exception"), *args, **kwargs)
self.signature = signature
def run(self, *args, **kwargs):
# Don't need to check the return value of report since it will
# handle all the UI reporting for us.
report.report_problem_in_memory(self.signature,
LIBREPORT_WAIT|LIBREPORT_RUN_CLI)
class MainExceptionWindow(TextWindow, AbstractMainExceptionWindow):
def __init__(self, shortTraceback=None, longTraceback=None, *args, **kwargs):
AbstractMainExceptionWindow.__init__(self, shortTraceback, longTraceback,
*args, **kwargs)
TextWindow.__init__(self, _("An unknown error has occurred"),
*args, **kwargs)
self._short_traceback = shortTraceback
self._menu_items = [(_("Run shell"), MAIN_RESPONSE_SHELL),
(_("Quit"), MAIN_RESPONSE_QUIT)]
allowDebug = kwargs.get("allowDebug", sys.stdout.isatty)
if allowDebug and allowDebug():
self._menu_items.insert(1, (_("Debug"), MAIN_RESPONSE_DEBUG))
# only enable error reporting if libreport is available
if LIBREPORT_AVAILABLE:
self._menu_items.insert(0, (_("Report Bug"), MAIN_RESPONSE_SAVE))
def run(self, *args, **kwargs):
self.print_header()
self._io.print(self._short_traceback)
self._io.print(_("What do you want to do now?"))
for (idx, item) in enumerate(self._menu_items):
self._io.print("%d) %s" % (idx + 1, item[0]))
ret = -1
num_menu_items = len(self._menu_items)
self._io.print()
while not (0 < ret <= num_menu_items):
ret = self._io.raw_input(_("Please make your choice from above: "))
try:
ret = int(ret)
except ValueError:
ret = -1
return self._menu_items[ret - 1][1]
class MessageWindow(TextWindow, AbstractMessageWindow):
def __init__(self, title, text, *args, **kwargs):
AbstractMessageWindow.__init__(self, title, text, *args, **kwargs)
TextWindow.__init__(self, title, *args, **kwargs)
self._text = text
def run(self, *args, **kwargs):
self.print_header()
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):
MessageWindow.__init__(self, title, text, *args, **kwargs)
def run(self, *args, **kwargs):
self.print_header()
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 = 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)
lower_answer = answer.decode("utf-8").lower().encode("utf-8")
answer = lower_answer or self._no_answer
if answer in (self._yes_answer, self._no_answer):
return answer == self._yes_answer
else:
self.run(*args, **kwargs)