Centralize encoding guesses, default to UTF-8

This might not be enough for print() and could need a locale.setlocale()
even though it is generally discouraged.

closes #1352
This commit is contained in:
Laurent Bachelier 2014-09-03 00:49:51 +02:00
commit 19a95dc0d6
4 changed files with 96 additions and 90 deletions

View file

@ -22,11 +22,9 @@ from __future__ import print_function
import atexit
from cmd import Cmd
import logging
import locale
import re
from optparse import OptionGroup, OptionParser, IndentedHelpFormatter
import os
import sys
from weboob.capabilities.base import FieldNotFound, BaseObject, UserError
from weboob.core import CallErrors
@ -113,9 +111,11 @@ class ReplApplication(Cmd, ConsoleApplication):
def __init__(self):
Cmd.__init__(self)
ConsoleApplication.__init__(self, ReplOptionParser(self.SYNOPSIS, version=self._get_optparse_version()))
self.intro = '\n'.join(('Welcome to %s%s%s v%s' % (self.BOLD, self.APPNAME, self.NC, self.VERSION),
'',
self.COPYRIGHT.encode(sys.stdout.encoding or locale.getpreferredencoding()),
self.COPYRIGHT.encode(self.encoding),
'This program is free software: you can redistribute it and/or modify',
'it under the terms of the GNU Affero General Public License as published by',
'the Free Software Foundation, either version 3 of the License, or',
@ -130,8 +130,6 @@ class ReplApplication(Cmd, ConsoleApplication):
self.formatter = None
self.commands_formatters = self.COMMANDS_FORMATTERS.copy()
ConsoleApplication.__init__(self, ReplOptionParser(self.SYNOPSIS, version=self._get_optparse_version()))
commands_help = self.get_commands_doc()
self._parser.commands = commands_help
self._parser.formatter = ReplOptionFormatter()
@ -170,7 +168,7 @@ class ReplApplication(Cmd, ConsoleApplication):
# of the same line instead of new line.
#self.prompt = self.BOLD + '%s> ' % self.APPNAME + self.NC
if len(self.working_path.get()):
wp_enc = unicode(self.working_path).encode(sys.stdout.encoding or locale.getpreferredencoding())
wp_enc = unicode(self.working_path).encode(self.encoding)
self.prompt = '%s:%s> ' % (self.APPNAME, wp_enc)
else:
self.prompt = '%s> ' % (self.APPNAME)
@ -210,13 +208,13 @@ class ReplApplication(Cmd, ConsoleApplication):
i = self.ask('Select a backend to proceed with "%s"' % id)
if not i.isdigit():
if not i in dict(e.backends):
print('Error: %s is not a valid backend' % i, file=sys.stderr)
print('Error: %s is not a valid backend' % i, file=self.stderr)
continue
backend_name = i
else:
i = int(i)
if i < 0 or i > len(e.backends):
print('Error: %s is not a valid choice' % i, file=sys.stderr)
print('Error: %s is not a valid choice' % i, file=self.stderr)
continue
backend_name = e.backends[i-1][0]
@ -350,7 +348,7 @@ class ReplApplication(Cmd, ConsoleApplication):
missing_fields = set(self.formatter.MANDATORY_FIELDS) - set(fields)
# If a mandatory field is not selected, do not use the customized formatter
if missing_fields:
print('Warning: you do not select enough mandatory fields for the formatter. Fallback to another. Hint: use option -f', file=sys.stderr)
print('Warning: you do not select enough mandatory fields for the formatter. Fallback to another. Hint: use option -f', file=self.stderr)
self.formatter = self.formatters_loader.build_formatter(ReplApplication.DEFAULT_FORMATTER)
if self.formatter.DISPLAYED_FIELDS is not None:
@ -360,7 +358,7 @@ class ReplApplication(Cmd, ConsoleApplication):
missing_fields = set(fields) - set(self.formatter.DISPLAYED_FIELDS + self.formatter.MANDATORY_FIELDS)
# If a selected field is not displayed, do not use the customized formatter
if missing_fields:
print('Warning: some selected fields will not be displayed by the formatter. Fallback to another. Hint: use option -f', file=sys.stderr)
print('Warning: some selected fields will not be displayed by the formatter. Fallback to another. Hint: use option -f', file=self.stderr)
self.formatter = self.formatters_loader.build_formatter(ReplApplication.DEFAULT_FORMATTER)
return self.weboob.do(self._do_complete, self.options.count, fields, function, *args, **kwargs)
@ -426,9 +424,9 @@ class ReplApplication(Cmd, ConsoleApplication):
except CallErrors as e:
self.bcall_errors_handler(e)
except BackendNotGiven as e:
print('Error: %s' % str(e), file=sys.stderr)
print('Error: %s' % str(e), file=self.stderr)
except NotEnoughArguments as e:
print('Error: not enough arguments. %s' % str(e), file=sys.stderr)
print('Error: not enough arguments. %s' % str(e), file=self.stderr)
except (KeyboardInterrupt, EOFError):
# ^C during a command process doesn't exit application.
print('\nAborted.')
@ -443,12 +441,12 @@ class ReplApplication(Cmd, ConsoleApplication):
pass
def default(self, line):
print('Unknown command: "%s"' % line, file=sys.stderr)
print('Unknown command: "%s"' % line, file=self.stderr)
cmd, arg, ignore = Cmd.parseline(self, line)
if cmd is not None:
names = set(name[3:] for name in self.get_names() if name.startswith('do_' + cmd))
if len(names) > 0:
print('Do you mean: %s?' % ', '.join(names), file=sys.stderr)
print('Do you mean: %s?' % ', '.join(names), file=self.stderr)
return 2
def completenames(self, text, *ignored):
@ -602,7 +600,7 @@ class ReplApplication(Cmd, ConsoleApplication):
lines[0] = '%s%s%s' % (self.BOLD, lines[0], self.NC)
self.stdout.write('%s\n' % '\n'.join(lines))
else:
print('Unknown command: "%s"' % arg, file=sys.stderr)
print('Unknown command: "%s"' % arg, file=self.stderr)
else:
cmds = self._parser.formatter.format_commands(self._parser.commands)
self.stdout.write('%s\n' % cmds)
@ -665,20 +663,20 @@ class ReplApplication(Cmd, ConsoleApplication):
if action in ('add', 'register'):
minfo = self.weboob.repositories.get_module_info(backend_name)
if minfo is None:
print('Module "%s" does not exist.' % backend_name, file=sys.stderr)
print('Module "%s" does not exist.' % backend_name, file=self.stderr)
return 1
else:
if not minfo.has_caps(self.CAPS):
print('Module "%s" is not supported by this application => skipping.' % backend_name, file=sys.stderr)
print('Module "%s" is not supported by this application => skipping.' % backend_name, file=self.stderr)
return 1
else:
if backend_name not in [backend.name for backend in self.weboob.iter_backends()]:
print('Backend "%s" does not exist => skipping.' % backend_name, file=sys.stderr)
print('Backend "%s" does not exist => skipping.' % backend_name, file=self.stderr)
return 1
if action in ('enable', 'disable', 'only', 'add', 'register', 'edit', 'remove'):
if not given_backend_names:
print('Please give at least a backend name.', file=sys.stderr)
print('Please give at least a backend name.', file=self.stderr)
return 2
given_backends = set(backend for backend in self.weboob.iter_backends() if backend.name in given_backend_names)
@ -691,7 +689,7 @@ class ReplApplication(Cmd, ConsoleApplication):
try:
self.enabled_backends.remove(backend)
except KeyError:
print('%s is not enabled' % backend.name, file=sys.stderr)
print('%s is not enabled' % backend.name, file=self.stderr)
elif action == 'only':
self.enabled_backends = set()
for backend in given_backends:
@ -743,11 +741,11 @@ class ReplApplication(Cmd, ConsoleApplication):
print('[%s] %s%-15s%s %s' % (loaded, self.BOLD, name, self.NC, info.description))
else:
print('Unknown action: "%s"' % action, file=sys.stderr)
print('Unknown action: "%s"' % action, file=self.stderr)
return 1
if len(self.enabled_backends) == 0:
print('Warning: no more backends are loaded. %s is probably unusable.' % self.APPNAME.capitalize(), file=sys.stderr)
print('Warning: no more backends are loaded. %s is probably unusable.' % self.APPNAME.capitalize(), file=self.stderr)
def complete_logging(self, text, line, begidx, endidx):
levels = ('debug', 'info', 'warning', 'error', 'quiet', 'default')
@ -788,8 +786,8 @@ class ReplApplication(Cmd, ConsoleApplication):
try:
level = levels[args[0]]
except KeyError:
print('Level "%s" does not exist.' % args[0], file=sys.stderr)
print('Availables: %s' % ' '.join(levels.iterkeys()), file=sys.stderr)
print('Level "%s" does not exist.' % args[0], file=self.stderr)
print('Availables: %s' % ' '.join(levels.iterkeys()), file=self.stderr)
return 2
else:
logging.root.setLevel(level)
@ -813,7 +811,7 @@ class ReplApplication(Cmd, ConsoleApplication):
try:
self.condition = ResultsCondition(line)
except ResultsConditionError as e:
print('%s' % e, file=sys.stderr)
print('%s' % e, file=self.stderr)
return 2
else:
if self.condition is None:
@ -840,7 +838,7 @@ class ReplApplication(Cmd, ConsoleApplication):
try:
count = int(line)
except ValueError:
print('Could not interpret "%s" as a number.' % line, file=sys.stderr)
print('Could not interpret "%s" as a number.' % line, file=self.stderr)
return 2
else:
if count > 0:
@ -902,7 +900,7 @@ class ReplApplication(Cmd, ConsoleApplication):
print('off' if self.options.no_keys else 'on')
else:
if args[2] not in ('on', 'off'):
print('Invalid value "%s". Please use "on" or "off" values.' % args[2], file=sys.stderr)
print('Invalid value "%s". Please use "on" or "off" values.' % args[2], file=self.stderr)
return 2
else:
if args[1] == 'header':
@ -910,7 +908,7 @@ class ReplApplication(Cmd, ConsoleApplication):
elif args[1] == 'keys':
self.options.no_keys = True if args[2] == 'off' else False
else:
print('Don\'t know which option to set. Available options: header, keys.', file=sys.stderr)
print('Don\'t know which option to set. Available options: header, keys.', file=self.stderr)
return 2
else:
if args[0] in self.formatters_loader.get_available_formatters():
@ -921,7 +919,7 @@ class ReplApplication(Cmd, ConsoleApplication):
self.DEFAULT_FORMATTER = self.set_formatter(args[0])
else:
print('Formatter "%s" is not available.\n' \
'Available formatters: %s.' % (args[0], ', '.join(self.formatters_loader.get_available_formatters())), file=sys.stderr)
'Available formatters: %s.' % (args[0], ', '.join(self.formatters_loader.get_available_formatters())), file=self.stderr)
return 1
else:
print('Default formatter: %s' % self.DEFAULT_FORMATTER)
@ -1077,7 +1075,7 @@ class ReplApplication(Cmd, ConsoleApplication):
if len(collections) == 1:
self.working_path.split_path = collections[0].split_path
else:
print(u"Path: %s not found" % unicode(self.working_path), file=sys.stderr)
print(u"Path: %s not found" % unicode(self.working_path), file=self.stderr)
self.working_path.restore()
return 1
@ -1150,7 +1148,7 @@ class ReplApplication(Cmd, ConsoleApplication):
collections = self.all_collections()
for collection in collections:
directories.add(collection.basename.encode(sys.stdout.encoding or locale.getpreferredencoding()))
directories.add(collection.basename.encode(self.encoding))
return [s[offs:] for s in directories if s.startswith(mline)]
@ -1170,10 +1168,10 @@ class ReplApplication(Cmd, ConsoleApplication):
try:
self.formatter = self.formatters_loader.build_formatter(name)
except FormatterLoadError as e:
print('%s' % e, file=sys.stderr)
print('%s' % e, file=self.stderr)
if self.DEFAULT_FORMATTER == name:
self.DEFAULT_FORMATTER = ReplApplication.DEFAULT_FORMATTER
print('Falling back to "%s".' % (self.DEFAULT_FORMATTER), file=sys.stderr)
print('Falling back to "%s".' % (self.DEFAULT_FORMATTER), file=self.stderr)
self.formatter = self.formatters_loader.build_formatter(self.DEFAULT_FORMATTER)
name = self.DEFAULT_FORMATTER
if self.options.no_header:
@ -1211,9 +1209,9 @@ class ReplApplication(Cmd, ConsoleApplication):
try:
self.formatter.format(obj=result, selected_fields=fields, alias=alias)
except FieldNotFound as e:
print(e, file=sys.stderr)
print(e, file=self.stderr)
except MandatoryFieldsNotFound as e:
print('%s Hint: select missing fields or use another formatter (ex: multiline).' % e, file=sys.stderr)
print('%s Hint: select missing fields or use another formatter (ex: multiline).' % e, file=self.stderr)
def flush(self):
self.formatter.flush()