summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HISTORY.txt9
-rw-r--r--docutils/core.py16
-rw-r--r--docutils/io.py29
-rw-r--r--docutils/parsers/rst/directives/misc.py17
-rw-r--r--docutils/parsers/rst/directives/tables.py8
-rw-r--r--docutils/writers/html4css1/__init__.py3
-rw-r--r--docutils/writers/latex2e/__init__.py3
-rwxr-xr-xtest/test_parsers/test_rst/test_directives/test_include.py8
-rwxr-xr-xtest/test_parsers/test_rst/test_directives/test_raw.py2
9 files changed, 56 insertions, 39 deletions
diff --git a/HISTORY.txt b/HISTORY.txt
index bde1fb7fd..dfa2b32cc 100644
--- a/HISTORY.txt
+++ b/HISTORY.txt
@@ -29,9 +29,18 @@ Changes Since 0.8.1
- Fix [ 2971827 ] and [ 3442827 ]
extras/roman.py moved to docutils/utils/roman.py
+* docutils/core.py:
+
+ - Catch and report InputError/OutputError
+ (unless the configuration setting "traceback" is true).
+
* docutils/io.py
- Fix [ 3395948 ] (Work around encoding problems in Py3k).
+ - FileInput/FileOutput: No system-exit on IOError.
+ Instead, the custom exceptions InputError/OutputError are raised
+ to allow handling by core.Publisher or a calling application.
+ The optional argument `handle_io_errors` (to be removed later) is ignored.
* docutils/utils.py -> docutils/utils/__init__.py
diff --git a/docutils/core.py b/docutils/core.py
index 48ef1a347..52d293be3 100644
--- a/docutils/core.py
+++ b/docutils/core.py
@@ -135,7 +135,7 @@ class Publisher:
if self.settings is None:
defaults = (settings_overrides or {}).copy()
# Propagate exceptions by default when used programmatically:
- defaults.setdefault('traceback', 1)
+ defaults.setdefault('traceback', True)
self.get_settings(settings_spec=settings_spec,
config_section=config_section,
**defaults)
@@ -221,7 +221,7 @@ class Publisher:
self.debugging_dumps()
raise
self.report_Exception(error)
- exit = 1
+ exit = True
exit_status = 1
self.debugging_dumps()
if (enable_exit_status and self.document
@@ -260,6 +260,10 @@ class Publisher:
self.report_SystemMessage(error)
elif isinstance(error, UnicodeEncodeError):
self.report_UnicodeError(error)
+ elif isinstance(error, io.InputError):
+ self.report_InputError(error)
+ elif isinstance(error, io.OutputError):
+ self.report_OutputError(error)
else:
print >>self._stderr, u'%s' % ErrorString(error)
print >>self._stderr, ("""\
@@ -275,6 +279,14 @@ command line used.""" % (__version__, __version_details__,
% (error.level,
utils.Reporter.levels[error.level]))
+ def report_InputError(self, error):
+ self._stderr.write(u'Unable to open source file for reading:\n'
+ u' %s\n' % ErrorString(error))
+
+ def report_OutputError(self, error):
+ self._stderr.write(u'Unable to open destination file for writing:\n'
+ u' %s\n' % ErrorString(error))
+
def report_UnicodeError(self, error):
data = error.object[error.start:error.end]
self._stderr.write(
diff --git a/docutils/io.py b/docutils/io.py
index 40630af55..7da07faad 100644
--- a/docutils/io.py
+++ b/docutils/io.py
@@ -17,6 +17,11 @@ from docutils import TransformSpec
from docutils._compat import b
from docutils.error_reporting import locale_encoding, ErrorString, ErrorOutput
+
+class InputError(IOError): pass
+class OutputError(IOError): pass
+
+
class Input(TransformSpec):
"""
@@ -184,7 +189,7 @@ class FileInput(Input):
"""
def __init__(self, source=None, source_path=None,
encoding=None, error_handler='strict',
- autoclose=True, handle_io_errors=True, mode='rU'):
+ autoclose=True, handle_io_errors=False, mode='rU'):
"""
:Parameters:
- `source`: either a file-like object (which is read directly), or
@@ -194,7 +199,7 @@ class FileInput(Input):
- `error_handler`: the encoding error handler to use.
- `autoclose`: close automatically after read (except when
`sys.stdin` is the source).
- - `handle_io_errors`: summarize I/O errors here, and exit?
+ - `handle_io_errors`: ignored.
- `mode`: how the file is to be opened (see standard function
`open`). The default 'rU' provides universal newline support
for text files.
@@ -216,12 +221,7 @@ class FileInput(Input):
try:
self.source = open(source_path, mode, **kwargs)
except IOError, error:
- if not handle_io_errors:
- raise
- print >>self._stderr, ErrorString(error)
- print >>self._stderr, (u'Unable to open source'
- u" file for reading ('%s'). Exiting." % source_path)
- sys.exit(1)
+ raise InputError(error.errno, error.strerror, source_path)
else:
self.source = sys.stdin
elif (sys.version_info >= (3,0) and
@@ -286,7 +286,7 @@ class FileOutput(Output):
def __init__(self, destination=None, destination_path=None,
encoding=None, error_handler='strict', autoclose=True,
- handle_io_errors=True):
+ handle_io_errors=False):
"""
:Parameters:
- `destination`: either a file-like object (which is written
@@ -294,8 +294,11 @@ class FileOutput(Output):
`destination_path` given).
- `destination_path`: a path to a file, which is opened and then
written.
+ - `encoding`: the text encoding of the output file.
+ - `error_handler`: the encoding error handler to use.
- `autoclose`: close automatically after write (except when
`sys.stdout` or `sys.stderr` is the destination).
+ - `handle_io_errors`: ignored.
"""
Output.__init__(self, destination, destination_path,
encoding, error_handler)
@@ -326,12 +329,8 @@ class FileOutput(Output):
try:
self.destination = open(self.destination_path, 'w', **kwargs)
except IOError, error:
- if not self.handle_io_errors:
- raise
- print >>self._stderr, ErrorString(error)
- print >>self._stderr, (u'Unable to open destination file'
- u" for writing ('%s'). Exiting." % self.destination_path)
- sys.exit(1)
+ raise OutputError(error.errno, error.strerror,
+ self.destination_path)
self.opened = True
def write(self, data):
diff --git a/docutils/parsers/rst/directives/misc.py b/docutils/parsers/rst/directives/misc.py
index 63775bb7c..d34b6266d 100644
--- a/docutils/parsers/rst/directives/misc.py
+++ b/docutils/parsers/rst/directives/misc.py
@@ -69,10 +69,10 @@ class Include(Directive):
try:
self.state.document.settings.record_dependencies.add(path)
include_file = io.FileInput(
- source_path=path, encoding=encoding,
- error_handler=(self.state.document.settings.\
- input_encoding_error_handler),
- handle_io_errors=None)
+ source_path=path,
+ encoding=encoding,
+ error_handler=
+ self.state.document.settings.input_encoding_error_handler)
except IOError, error:
raise self.severe(u'Problems with "%s" directive path:\n%s.' %
(self.name, ErrorString(error)))
@@ -198,11 +198,10 @@ class Raw(Directive):
self.options['file']))
path = utils.relative_path(None, path)
try:
- raw_file = io.FileInput(
- source_path=path, encoding=encoding,
- error_handler=(self.state.document.settings.\
- input_encoding_error_handler),
- handle_io_errors=None)
+ eh = self.state.document.settings.input_encoding_error_handler
+ raw_file = io.FileInput(source_path=path,
+ encoding=encoding,
+ error_handler=eh)
# TODO: currently, raw input files are recorded as
# dependencies even if not used for the chosen output format.
self.state.document.settings.record_dependencies.add(path)
diff --git a/docutils/parsers/rst/directives/tables.py b/docutils/parsers/rst/directives/tables.py
index fcf3c2b83..25b5f50d8 100644
--- a/docutils/parsers/rst/directives/tables.py
+++ b/docutils/parsers/rst/directives/tables.py
@@ -271,10 +271,10 @@ class CSVTable(Table):
try:
self.state.document.settings.record_dependencies.add(source)
csv_file = io.FileInput(
- source_path=source, encoding=encoding,
- error_handler=(self.state.document.settings.\
- input_encoding_error_handler),
- handle_io_errors=None)
+ source_path=source,
+ encoding=encoding,
+ error_handler=
+ self.state.document.settings.input_encoding_error_handler)
csv_data = csv_file.read().splitlines()
except IOError, error:
severe = self.state_machine.reporter.severe(
diff --git a/docutils/writers/html4css1/__init__.py b/docutils/writers/html4css1/__init__.py
index 761b9f601..a54ec077c 100644
--- a/docutils/writers/html4css1/__init__.py
+++ b/docutils/writers/html4css1/__init__.py
@@ -373,8 +373,7 @@ class HTMLTranslator(nodes.NodeVisitor):
if self.settings.embed_stylesheet:
try:
content = io.FileInput(source_path=path,
- encoding='utf-8',
- handle_io_errors=False).read()
+ encoding='utf-8').read()
self.settings.record_dependencies.add(path)
except IOError, err:
msg = u"Cannot embed stylesheet '%s': %s." % (
diff --git a/docutils/writers/latex2e/__init__.py b/docutils/writers/latex2e/__init__.py
index 8e4f55da5..8557203c8 100644
--- a/docutils/writers/latex2e/__init__.py
+++ b/docutils/writers/latex2e/__init__.py
@@ -1179,8 +1179,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
path = base + '.sty' # ensure extension
try:
content = io.FileInput(source_path=path,
- encoding='utf-8',
- handle_io_errors=False).read()
+ encoding='utf-8').read()
self.settings.record_dependencies.add(path)
except IOError, err:
msg = u"Cannot embed stylesheet '%s':\n %s." % (
diff --git a/test/test_parsers/test_rst/test_directives/test_include.py b/test/test_parsers/test_rst/test_directives/test_include.py
index 2d159cd2b..168d452f6 100755
--- a/test/test_parsers/test_rst/test_directives/test_include.py
+++ b/test/test_parsers/test_rst/test_directives/test_include.py
@@ -212,7 +212,7 @@ A paragraph.
<system_message level="4" line="4" source="test data" type="SEVERE">
<paragraph>
Problems with "include" directive path:
- IOError: [Errno 2] No such file or directory: 'nonexistent.txt'.
+ InputError: [Errno 2] No such file or directory: 'nonexistent.txt'.
<literal_block xml:space="preserve">
.. include:: nonexistent.txt
<paragraph>
@@ -414,7 +414,7 @@ u"""\
<system_message level="4" line="3" source="test data" type="SEVERE">
<paragraph>
Problems with "include" directive path:
- IOError: [Errno 2] No such file or directory: '\u043c\u0438\u0440.txt'.
+ InputError: [Errno 2] No such file or directory: '\u043c\u0438\u0440.txt'.
<literal_block xml:space="preserve">
.. include:: \u043c\u0438\u0440.txt
"""],
@@ -458,7 +458,7 @@ Testing errors in included file:
<system_message level="4" line="12" source="%(source)s" type="SEVERE">
<paragraph>
Problems with "include" directive path:
- IOError: [Errno 2] No such file or directory: '%(nonexistent)s'.
+ InputError: [Errno 2] No such file or directory: '%(nonexistent)s'.
<literal_block xml:space="preserve">
.. include:: <nonexistent>
<system_message level="3" line="14" source="%(source)s" type="ERROR">
@@ -697,7 +697,7 @@ Nonexistent standard include data file:
<system_message level="4" line="3" source="test data" type="SEVERE">
<paragraph>
Problems with "include" directive path:
- IOError: [Errno 2] No such file or directory: '%s'.
+ InputError: [Errno 2] No such file or directory: '%s'.
<literal_block xml:space="preserve">
.. include:: <nonexistent>
""" % nonexistent_rel],
diff --git a/test/test_parsers/test_rst/test_directives/test_raw.py b/test/test_parsers/test_rst/test_directives/test_raw.py
index b251edba3..e49e5cd03 100755
--- a/test/test_parsers/test_rst/test_directives/test_raw.py
+++ b/test/test_parsers/test_rst/test_directives/test_raw.py
@@ -158,7 +158,7 @@ Raw input file is UTF-16-encoded, and is not valid ASCII.
<system_message level="4" line="1" source="test data" type="SEVERE">
<paragraph>
Problems with "raw" directive path:
- IOError: [Errno 2] No such file or directory: 'non-existent.file'.
+ InputError: [Errno 2] No such file or directory: 'non-existent.file'.
<literal_block xml:space="preserve">
.. raw:: html
:file: non-existent.file