diff --git a/src/calibre/ebooks/oeb/polish/check/images.py b/src/calibre/ebooks/oeb/polish/check/images.py index 2b7dac850a..5cadc0ad86 100644 --- a/src/calibre/ebooks/oeb/polish/check/images.py +++ b/src/calibre/ebooks/oeb/polish/check/images.py @@ -12,6 +12,7 @@ from PIL import Image from calibre import as_unicode from calibre.ebooks.oeb.polish.check.base import BaseError, WARN from calibre.ebooks.oeb.polish.check.parsing import EmptyFile +from polyglot.builtins import error_message class InvalidImage(BaseError): @@ -59,7 +60,7 @@ def check_raster_images(name, mt, raw): try: i = Image.open(BytesIO(raw)) except Exception as e: - errors.append(InvalidImage(as_unicode(e.message), name)) + errors.append(InvalidImage(as_unicode(error_message(e)), name)) else: if i.mode == 'CMYK': errors.append(CMYKImage(_('Image is in the CMYK colorspace'), name)) diff --git a/src/calibre/ebooks/oeb/polish/check/parsing.py b/src/calibre/ebooks/oeb/polish/check/parsing.py index 1ef9fef430..130bf8751d 100644 --- a/src/calibre/ebooks/oeb/polish/check/parsing.py +++ b/src/calibre/ebooks/oeb/polish/check/parsing.py @@ -18,7 +18,7 @@ from calibre.ebooks.oeb.polish.pretty import pretty_script_or_style as fix_style from calibre.ebooks.oeb.polish.utils import PositionFinder, guess_type from calibre.ebooks.oeb.polish.check.base import BaseError, WARN, ERROR, INFO from calibre.ebooks.oeb.base import OEB_DOCS, XHTML_NS, urlquote, URL_SAFE, XHTML -from polyglot.builtins import iteritems, unicode_type +from polyglot.builtins import iteritems, unicode_type, error_message HTML_ENTITTIES = frozenset(html5_entities) XML_ENTITIES = {'lt', 'gt', 'amp', 'apos', 'quot'} @@ -297,9 +297,9 @@ def check_xml_parsing(name, mt, raw): line, col = err.position except: line = col = None - return errors + [errcls(err.message, name, line, col)] + return errors + [errcls(error_message(err), name, line, col)] except Exception as err: - return errors + [errcls(err.message, name)] + return errors + [errcls(error_message(err), name)] if mt in OEB_DOCS: if root.nsmap.get(root.prefix, None) != XHTML_NS: diff --git a/src/calibre/gui2/dialogs/metadata_bulk.py b/src/calibre/gui2/dialogs/metadata_bulk.py index 8c53ff7c0c..6b82d69b37 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.py +++ b/src/calibre/gui2/dialogs/metadata_bulk.py @@ -32,7 +32,7 @@ from calibre.utils.date import qt_to_dt, internal_iso_format_string from calibre.utils.icu import capitalize, sort_key from calibre.utils.titlecase import titlecase from calibre.gui2.widgets import LineEditECM -from polyglot.builtins import iteritems, itervalues, unicode_type +from polyglot.builtins import iteritems, itervalues, unicode_type, error_message Settings = namedtuple('Settings', 'remove_all remove add au aus do_aus rating pub do_series do_autonumber ' @@ -885,7 +885,7 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): def s_r_set_colors(self): if self.s_r_error is not None: col = 'rgb(255, 0, 0, 20%)' - self.test_result.setText(self.s_r_error.message) + self.test_result.setText(error_message(self.s_r_error)) else: col = 'rgb(0, 255, 0, 20%)' self.test_result.setStyleSheet('QLineEdit { color: black; ' @@ -1155,7 +1155,7 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): if self.s_r_error is not None and do_sr: error_dialog(self, _('Search/replace invalid'), - _('Search/replace is invalid: %s')%self.s_r_error.message, + _('Search/replace is invalid: %s')%error_message(self.s_r_error), show=True) return False self.changed = bool(self.ids) diff --git a/src/calibre/gui2/tweak_book/search.py b/src/calibre/gui2/tweak_book/search.py index de8397b5ca..84f859e0cf 100644 --- a/src/calibre/gui2/tweak_book/search.py +++ b/src/calibre/gui2/tweak_book/search.py @@ -34,7 +34,7 @@ from calibre.gui2.tweak_book.widgets import BusyCursor from calibre.gui2.widgets2 import FlowLayout, HistoryComboBox from calibre.utils.icu import primary_contains from calibre.ebooks.conversion.search_replace import REGEX_FLAGS, compile_regular_expression -from polyglot.builtins import iteritems, unicode_type, range +from polyglot.builtins import iteritems, unicode_type, range, error_message # The search panel {{{ @@ -1279,7 +1279,7 @@ def validate_search_request(name, searchable_names, has_marked_text, state, gui_ class InvalidRegex(regex.error): def __init__(self, raw, e): - regex.error.__init__(self, e.message) + regex.error.__init__(self, error_message(e)) self.regex = raw @@ -1399,10 +1399,10 @@ def run_search( except InvalidRegex as e: return error_dialog(gui_parent, _('Invalid regex'), '

' + _( 'The regular expression you entered is invalid:

{0}
With error: {1}').format( - prepare_string_for_xml(e.regex), e.message), show=True) + prepare_string_for_xml(e.regex), error_message(e)), show=True) except NoSuchFunction as e: return error_dialog(gui_parent, _('No such function'), '

' + _( - 'No replace function with the name: %s exists') % prepare_string_for_xml(e.message), show=True) + 'No replace function with the name: %s exists') % prepare_string_for_xml(error_message(e)), show=True) def no_match(): QApplication.restoreOverrideCursor() diff --git a/src/calibre/gui2/tweak_book/text_search.py b/src/calibre/gui2/tweak_book/text_search.py index eed04a90d0..23794a6577 100644 --- a/src/calibre/gui2/tweak_book/text_search.py +++ b/src/calibre/gui2/tweak_book/text_search.py @@ -17,7 +17,7 @@ from calibre.gui2.tweak_book import tprefs, editors, current_container from calibre.gui2.tweak_book.search import get_search_regex, InvalidRegex, initialize_search_request from calibre.gui2.tweak_book.widgets import BusyCursor from calibre.gui2.widgets2 import HistoryComboBox -from polyglot.builtins import iteritems, unicode_type +from polyglot.builtins import iteritems, unicode_type, error_message # UI {{{ @@ -166,7 +166,7 @@ def run_text_search(search, current_editor, current_editor_name, searchable_name except InvalidRegex as e: return error_dialog(gui_parent, _('Invalid regex'), '

' + _( 'The regular expression you entered is invalid:

{0}
With error: {1}').format( - prepare_string_for_xml(e.regex), e.message), show=True) + prepare_string_for_xml(e.regex), error_message(e)), show=True) editor, where, files, do_all, marked = initialize_search_request(search, 'count', current_editor, current_editor_name, searchable_names) with BusyCursor(): if editor is not None: diff --git a/src/calibre/srv/auto_reload.py b/src/calibre/srv/auto_reload.py index 4c0d3dbdf7..dca62448ba 100644 --- a/src/calibre/srv/auto_reload.py +++ b/src/calibre/srv/auto_reload.py @@ -17,7 +17,7 @@ from calibre.srv.standalone import create_option_parser from calibre.srv.utils import create_sock_pair from calibre.srv.web_socket import DummyHandler from calibre.utils.monotonic import monotonic -from polyglot.builtins import itervalues +from polyglot.builtins import itervalues, error_message from polyglot.queue import Queue, Empty MAX_RETRIES = 10 @@ -300,7 +300,7 @@ class Worker(object): time.sleep(0.01) compile_srv() except CompileFailure as e: - self.log.error(e.message) + self.log.error(error_message(e)) time.sleep(0.1 * self.retry_count) if self.retry_count < MAX_RETRIES and self.wakeup is not None: self.wakeup() # Force a restart diff --git a/src/calibre/srv/http_request.py b/src/calibre/srv/http_request.py index 02afb5252f..376139cc58 100644 --- a/src/calibre/srv/http_request.py +++ b/src/calibre/srv/http_request.py @@ -16,6 +16,7 @@ from calibre.srv.loop import Connection, READ, WRITE from calibre.srv.utils import MultiDict, HTTP1, HTTP11, Accumulator from polyglot import http_client, reprlib from polyglot.urllib import unquote +from polyglot.builtins import error_message protocol_map = {(1, 0):HTTP1, (1, 1):HTTP11} quoted_slash = re.compile(br'%2[fF]') @@ -281,7 +282,7 @@ class HTTPRequest(Connection): try: self.scheme, self.path, self.query = parse_uri(uri) except HTTPSimpleResponse as e: - return self.simple_response(e.http_code, e.message, close_after_response=False) + return self.simple_response(e.http_code, error_message(e), close_after_response=False) self.header_line_too_long_error_code = http_client.REQUEST_ENTITY_TOO_LARGE self.set_state(READ, self.parse_header_line, HTTPHeaderParser(), Accumulator()) # }}} diff --git a/src/calibre/srv/http_response.py b/src/calibre/srv/http_response.py index a4fcdef924..3c97610129 100644 --- a/src/calibre/srv/http_response.py +++ b/src/calibre/srv/http_response.py @@ -27,6 +27,7 @@ from calibre.srv.utils import ( from calibre.utils.speedups import ReadOnlyFileBuffer from calibre.utils.monotonic import monotonic from polyglot import http_client, reprlib +from polyglot.builtins import error_message Range = namedtuple('Range', 'start stop size') MULTIPART_SEPARATOR = uuid.uuid4().hex @@ -489,7 +490,7 @@ class HTTPConnection(HTTPRequest): eh['WWW-Authenticate'] = e.authenticate if e.log: self.log.warn(e.log) - return self.simple_response(e.http_code, msg=e.message or '', close_after_response=e.close_connection, extra_headers=eh) + return self.simple_response(e.http_code, msg=error_message(e) or '', close_after_response=e.close_connection, extra_headers=eh) reraise(etype, e, tb) data, output = result diff --git a/src/calibre/srv/standalone.py b/src/calibre/srv/standalone.py index 9f585510cc..e2fd973341 100644 --- a/src/calibre/srv/standalone.py +++ b/src/calibre/srv/standalone.py @@ -24,6 +24,7 @@ from calibre.srv.utils import RotatingLog from calibre.utils.config import prefs from calibre.utils.localization import localize_user_manual_link from calibre.utils.lock import singleinstance +from polyglot.builtins import error_message def daemonize(): # {{{ @@ -213,7 +214,7 @@ def main(args=sys.argv): from calibre.utils.logging import default_log return auto_reload(default_log, listen_on=opts.listen_on) except NoAutoReload as e: - raise SystemExit(e.message) + raise SystemExit(error_message(e)) opts.auto_reload_port = int(os.environ.get('CALIBRE_AUTORELOAD_PORT', 0)) opts.allow_console_print = 'CALIBRE_ALLOW_CONSOLE_PRINT' in os.environ if opts.log and os.path.isdir(opts.log): diff --git a/src/calibre/utils/exim.py b/src/calibre/utils/exim.py index 9011340f53..7cc77eaf82 100644 --- a/src/calibre/utils/exim.py +++ b/src/calibre/utils/exim.py @@ -12,7 +12,7 @@ from calibre.constants import config_dir, iswindows from calibre.utils.config_base import prefs, StringConfig, create_global_prefs from calibre.utils.config import JSONConfig from calibre.utils.filenames import samefile -from polyglot.builtins import iteritems, raw_input +from polyglot.builtins import iteritems, raw_input, error_message from polyglot.binary import as_hex_unicode @@ -439,7 +439,7 @@ def run_importer(): try: importer = Importer(export_dir) except ValueError as err: - raise SystemExit(err.message) + raise SystemExit(error_message(err)) import_dir = input_unicode('Enter path to an empty folder (all libraries will be created inside this folder): ').rstrip('\r') if not os.path.exists(import_dir): diff --git a/src/calibre/utils/formatter.py b/src/calibre/utils/formatter.py index 5581d1eb16..e0ccd216d5 100644 --- a/src/calibre/utils/formatter.py +++ b/src/calibre/utils/formatter.py @@ -13,7 +13,7 @@ import re, string, traceback, numbers from calibre import prints from calibre.constants import DEBUG from calibre.utils.formatter_functions import formatter_functions -from polyglot.builtins import unicode_type +from polyglot.builtins import unicode_type, error_message class _Parser(object): @@ -379,7 +379,7 @@ class TemplateFormatter(string.Formatter): traceback.print_exc() if column_name: prints('Error evaluating column named:', column_name) - ans = error_value + ' ' + e.message + ans = error_value + ' ' + error_message(e) return ans diff --git a/src/calibre/utils/rapydscript.py b/src/calibre/utils/rapydscript.py index fb8da3a8e0..4c73700ab8 100644 --- a/src/calibre/utils/rapydscript.py +++ b/src/calibre/utils/rapydscript.py @@ -22,7 +22,7 @@ from calibre.utils.filenames import atomic_rename from calibre.utils.terminal import ANSIStream from duktape import Context, JSError, to_python from lzma.xz import compress, decompress -from polyglot.builtins import itervalues, range, exec_path, raw_input +from polyglot.builtins import itervalues, range, exec_path, raw_input, error_message from polyglot.queue import Empty, Queue COMPILER_PATH = 'rapydscript/compiler.js.xz' @@ -372,7 +372,7 @@ class Repl(Thread): self.from_repl.put(val[0]) except Exception as e: if isinstance(e, JSError): - print(e.stack or e.message, file=sys.stderr) + print(e.stack or error_message(e), file=sys.stderr) else: import traceback traceback.print_exc() @@ -448,9 +448,9 @@ def main(args=sys.argv): data = compile_pyj(sys.stdin.read().decode(enc), libdir=libdir, private_scope=not args.no_private_scope, omit_baselib=args.omit_baselib) print(data.encode(enc)) except JSError as e: - raise SystemExit(e.message) + raise SystemExit(error_message(e)) except CompileFailure as e: - raise SystemExit(e.message) + raise SystemExit(error_message(e)) def entry(): diff --git a/src/calibre/utils/serve_coffee.py b/src/calibre/utils/serve_coffee.py index fc8bddb036..114aa7b1a2 100644 --- a/src/calibre/utils/serve_coffee.py +++ b/src/calibre/utils/serve_coffee.py @@ -17,6 +17,7 @@ from threading import Lock, local from polyglot import socketserver from polyglot.http_server import HTTPServer, SimpleHTTPRequestHandler +from polyglot.builtins import error_message # Compiler {{{ @@ -39,7 +40,7 @@ def compile_coffeescript(raw, filename=None): try: ans = compiler().eval('CoffeeScript.compile(src)') except JSError as e: - return u'', (e.message,) + return u'', (error_message(e),) return ans, () # }}} diff --git a/src/css_selectors/parser.py b/src/css_selectors/parser.py index 1a90bb335d..d9575eef3c 100644 --- a/src/css_selectors/parser.py +++ b/src/css_selectors/parser.py @@ -375,8 +375,6 @@ def parse(css): # message = "%s at %s -> %r" % ( # e, stream.used, stream.peek()) # e.msg = message -# if sys.version_info < (2,6): -# e.message = message # e.args = tuple([message]) # raise diff --git a/src/duktape/__init__.py b/src/duktape/__init__.py index f4f7032444..e7dd525c96 100644 --- a/src/duktape/__init__.py +++ b/src/duktape/__init__.py @@ -17,6 +17,7 @@ from polyglot.builtins import reraise from calibre.constants import iswindows from calibre.utils.filenames import atomic_rename +from polyglot.builtins import error_message Context_, undefined = dukpy.Context, dukpy.undefined @@ -122,7 +123,7 @@ def readfile(path, enc='utf-8'): except UnicodeDecodeError as e: return None, '', 'Failed to decode the file: %s with specified encoding: %s' % (path, enc) except EnvironmentError as e: - return [None, errno.errorcode[e.errno], 'Failed to read from file: %s with error: %s' % (path, e.message or e)] + return [None, errno.errorcode[e.errno], 'Failed to read from file: %s with error: %s' % (path, error_message(e) or e)] def atomic_write(name, raw): @@ -143,7 +144,7 @@ def writefile(path, data, enc='utf-8'): except UnicodeEncodeError as e: return ['', 'Failed to encode the data for file: %s with specified encoding: %s' % (path, enc)] except EnvironmentError as e: - return [errno.errorcode[e.errno], 'Failed to write to file: %s with error: %s' % (path, e.message or e)] + return [errno.errorcode[e.errno], 'Failed to write to file: %s with error: %s' % (path, error_message(e) or e)] return [None, None] @@ -217,7 +218,7 @@ class JSError(Exception): def as_dict(self): return { 'name':self.name or undefined, - 'message': self.js_message or self.message, + 'message': self.js_message or error_message(self), 'fileName': self.fileName or undefined, 'lineNumber': self.lineNumber or undefined, 'stack': self.stack or undefined diff --git a/src/lzma/xz.py b/src/lzma/xz.py index 5237db1de1..94cb12665c 100644 --- a/src/lzma/xz.py +++ b/src/lzma/xz.py @@ -15,6 +15,7 @@ from binascii import crc32 as _crc32 from calibre.ptempfile import SpooledTemporaryFile from lzma.errors import NotXZ, InvalidXZ, lzma +from polyglot.builtins import error_message HEADER_MAGIC = b'\xfd7zXZ\0' FOOTER_MAGIC = b'YZ' @@ -190,7 +191,7 @@ class LZMA2Filter(object): lzma.decompress2(f.read, f.seek, write, self.props, self.bufsize) except lzma.error as e: raise InvalidXZ( - 'Failed to decode LZMA2 block with error code: %s' % e.message + 'Failed to decode LZMA2 block with error code: %s' % error_message(e) ) self.crc.finish() diff --git a/src/polyglot/builtins.py b/src/polyglot/builtins.py index da0a0cb857..d70a207da8 100644 --- a/src/polyglot/builtins.py +++ b/src/polyglot/builtins.py @@ -38,6 +38,12 @@ if is_py3: long_type = int raw_input = input + def error_message(exc): + args = getattr(exc, 'args', None) + if args and isinstance(args[0], unicode_type): + return args[0] + return unicode_type(exc) + def iteritems(d): return iter(d.items()) @@ -83,6 +89,12 @@ else: cmp = builtins.cmp int_to_byte = chr + def error_message(exc): + ans = exc.message + if isinstance(ans, bytes): + ans = ans.decode('utf-8', 'replace') + return ans + def iteritems(d): return d.iteritems() diff --git a/src/tinycss/media3.py b/src/tinycss/media3.py index 5d91c9f080..e75ec0b315 100644 --- a/src/tinycss/media3.py +++ b/src/tinycss/media3.py @@ -8,6 +8,8 @@ __copyright__ = '2014, Kovid Goyal ' from tinycss.css21 import CSS21Parser from tinycss.parsing import remove_whitespace, split_on_comma, ParseError +from polyglot.builtins import error_message + class MediaQuery(object): @@ -27,12 +29,14 @@ class MediaQuery(object): self.negated == getattr(other, 'negated', None) and \ self.expressions == getattr(other, 'expressions', None) + class MalformedExpression(Exception): def __init__(self, tok, msg): Exception.__init__(self, msg) self.tok = tok + class CSSMedia3Parser(CSS21Parser): ''' Parse media queries as defined by the CSS 3 media module ''' @@ -96,9 +100,8 @@ class CSSMedia3Parser(CSS21Parser): expressions.append((media_feature, expr)) except MalformedExpression as err: - errors.extend(ParseError(err.tok, err.message)) + errors.extend(ParseError(err.tok, error_message(err))) media_type, negated, expressions = 'all', True, () queries.append(MediaQuery(media_type or 'all', expressions=tuple(expressions), negated=negated)) return queries -