Skip to content

Commit 592cffb

Browse files
committed
CLI/Display: use utf-8 (or non-ascii) encoding (#400)
We were hardcoding the use of 'ascii' encoding in CLI/Display.py which was not a good idea. Default string encoding in Python 2 is 'ascii', while it is 'utf-8' in Python 3, so we can't just use str.encode() without argument. We don't want to use 'ascii' encoding, so let's force to 'utf-8' encoding unless the system provides a default to some other encoding. In Python 3, it will default to 'utf-8' which is what we want anyway. This patch also fixes the scope of ValueError exception handling in clubak() for Display() object initializer. UnicodeEncodingError actually inherits from ValueError so this error appeared as an option mismatch to the user but this was definitively not. Any other ValueError like UnicodeEncodingError is now catched in Clubak.main() instead. Fixes #400 (clubak --diff fails on non-ascii text) Change-Id: I9ea1e49df9c39bfa03f35f88f8b20a65ad6c98b1
1 parent 9b3a239 commit 592cffb

File tree

3 files changed

+23
-12
lines changed

3 files changed

+23
-12
lines changed

lib/ClusterShell/CLI/Clubak.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -161,15 +161,17 @@ def clubak():
161161
# Display results
162162
try:
163163
disp = Display(options)
164-
if options.debug:
165-
std_group_resolver().set_verbosity(1)
166-
print("clubak: line_mode=%s gather=%s tree_depth=%d"
167-
% (bool(options.line_mode), bool(disp.gather), tree._depth()),
168-
file=sys.stderr)
169-
display(tree, disp, disp.gather or disp.regroup, \
170-
options.trace_mode, enable_nodeset_key is not False)
171164
except ValueError as exc:
172165
parser.error("option mismatch (%s)" % exc)
166+
return
167+
168+
if options.debug:
169+
std_group_resolver().set_verbosity(1)
170+
print("clubak: line_mode=%s gather=%s tree_depth=%d"
171+
% (bool(options.line_mode), bool(disp.gather), tree._depth()),
172+
file=sys.stderr)
173+
display(tree, disp, disp.gather or disp.regroup, \
174+
options.trace_mode, enable_nodeset_key is not False)
173175

174176
def main():
175177
"""main script function"""

lib/ClusterShell/CLI/Display.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@
3636
THREE_CHOICES = ["never", "always", "auto"]
3737
WHENCOLOR_CHOICES = THREE_CHOICES # deprecated; use THREE_CHOICES
3838

39+
if sys.getdefaultencoding() == 'ascii':
40+
STRING_ENCODING = 'utf-8' # enforce UTF-8 with Python 2
41+
else:
42+
STRING_ENCODING = sys.getdefaultencoding()
43+
44+
3945
# Python 3 compat: wrappers for standard streams
4046
def sys_stdin():
4147
return getattr(sys.stdin, 'buffer', sys.stdin)
@@ -166,21 +172,21 @@ def format_header(self, nodeset, indent=0):
166172
(indstr, self.SEP,
167173
indstr, self._format_nodeset(nodeset), nodecntstr,
168174
indstr, self.SEP))
169-
return hdr.encode('ascii') + b'\n'
175+
return hdr.encode(STRING_ENCODING) + b'\n'
170176

171177
def print_line(self, nodeset, line):
172178
"""Display a line with optional label."""
173179
if self.label:
174180
prefix = self.color_stdout_fmt % ("%s: " % nodeset)
175-
self.out.write(prefix.encode('ascii') + line + b'\n')
181+
self.out.write(prefix.encode(STRING_ENCODING) + line + b'\n')
176182
else:
177183
self.out.write(line + b'\n')
178184

179185
def print_line_error(self, nodeset, line):
180186
"""Display an error line with optional label."""
181187
if self.label:
182188
prefix = self.color_stderr_fmt % ("%s: " % nodeset)
183-
self.err.write(prefix.encode('ascii') + line + b'\n')
189+
self.err.write(prefix.encode(STRING_ENCODING) + line + b'\n')
184190
else:
185191
self.err.write(line + b'\n')
186192

@@ -234,7 +240,7 @@ def _print_diff(self, nodeset, content):
234240
else:
235241
output += line
236242
output += '\n'
237-
self.out.write(output.encode('ascii'))
243+
self.out.write(output.encode(STRING_ENCODING))
238244

239245
def _print_lines(self, nodeset, msg):
240246
"""Display a MsgTree buffer by line with prefixed header."""
@@ -243,7 +249,7 @@ def _print_lines(self, nodeset, msg):
243249
header = self.color_stdout_fmt % \
244250
("%s: " % self._format_nodeset(nodeset))
245251
for line in msg:
246-
out.write(header.encode('ascii') + line + b'\n')
252+
out.write(header.encode(STRING_ENCODING) + line + b'\n')
247253
else:
248254
for line in msg:
249255
out.write(line + b'\n')

tests/CLIClubakTest.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,9 @@ def test_009_diff(self):
169169
b"line_mode=False gather=True tree_depth=1\n")
170170
self._clubak_t(["--diff", "-L"], b"foo1: bar\nfoo2: bar", b'', 2,
171171
b"error: option mismatch (diff not supported in line_mode)\n")
172+
# GH #400
173+
self._clubak_t(["--diff"], b"host1: \xc3\xa5\nhost2: a\nhost2: b\nhost1: b\n",
174+
b"--- host1\n+++ host2\n@@ -1,2 +1,2 @@\n- \xc3\xa5\n+ a\n b\n")
172175

173176

174177
class CLIClubakTestGroupsConf(CLIClubakTest):

0 commit comments

Comments
 (0)