diff --git a/sphinx/environment.py b/sphinx/environment.py index ec65e5d241..5b92c03767 100644 --- a/sphinx/environment.py +++ b/sphinx/environment.py @@ -493,14 +493,14 @@ class BuildEnvironment: def warn_and_replace(self, error): """Custom decoding error handler that warns and replaces.""" - linestart = error.object.rfind('\n', 0, error.start) - lineend = error.object.find('\n', error.start) + linestart = error.object.rfind(b'\n', 0, error.start) + lineend = error.object.find(b'\n', error.start) if lineend == -1: lineend = len(error.object) - lineno = error.object.count('\n', 0, error.start) + 1 + lineno = error.object.count(b'\n', 0, error.start) + 1 self.warn(self.docname, 'undecodable source characters, ' 'replacing with "?": %r' % - (error.object[linestart+1:error.start] + '>>>' + - error.object[error.start:error.end] + '<<<' + + (error.object[linestart+1:error.start] + b'>>>' + + error.object[error.start:error.end] + b'<<<' + error.object[error.end:lineend]), lineno) return (u'?', error.end) @@ -590,12 +590,13 @@ class BuildEnvironment: def __init__(self_, *args, **kwds): # don't call sys.exit() on IOErrors kwds['handle_io_errors'] = False + kwds['error_handler'] = 'sphinx' # py3: handle error on open. FileInput.__init__(self_, *args, **kwds) def decode(self_, data): - if isinstance(data, text_type): + if isinstance(data, text_type): # py3: `data` already decoded. return data - return data.decode(self_.encoding, 'sphinx') + return data.decode(self_.encoding, 'sphinx') # py2: decoding def read(self_): data = FileInput.read(self_) diff --git a/tests/test_env.py b/tests/test_env.py index 11e73edfef..443f249c71 100644 --- a/tests/test_env.py +++ b/tests/test_env.py @@ -10,7 +10,7 @@ """ from six import PY3 -from util import TestApp, remove_unicode_literals, path +from util import TestApp, remove_unicode_literals, path, with_app from sphinx.builders.html import StandaloneHTMLBuilder from sphinx.builders.latex import LaTeXBuilder @@ -95,6 +95,20 @@ def test_second_update(): assert 'autodoc' not in env.all_docs assert 'autodoc' not in env.found_docs + +@with_app(srcdir='(empty)') +def test_undecodable_source_reading_emit_warnings(app): + # issue #1524 + warnings[:] = [] + app.env.set_warnfunc(lambda *args: warnings.append(args)) + (app.srcdir / 'contents.rst').write_bytes(b'1\xbb2') + _, _, it = app.env.update(app.config, app.srcdir, app.doctreedir, app) + list(it) # the generator does all the work + assert warning_emitted( + 'contents', 'undecodable source characters, replacing with "?":' + ) + + def test_object_inventory(): refs = env.domaindata['py']['objects']