diff options
-rw-r--r-- | HISTORY.txt | 9 | ||||
-rw-r--r-- | docutils/core.py | 16 | ||||
-rw-r--r-- | docutils/io.py | 29 | ||||
-rw-r--r-- | docutils/parsers/rst/directives/misc.py | 17 | ||||
-rw-r--r-- | docutils/parsers/rst/directives/tables.py | 8 | ||||
-rw-r--r-- | docutils/writers/html4css1/__init__.py | 3 | ||||
-rw-r--r-- | docutils/writers/latex2e/__init__.py | 3 | ||||
-rwxr-xr-x | test/test_parsers/test_rst/test_directives/test_include.py | 8 | ||||
-rwxr-xr-x | test/test_parsers/test_rst/test_directives/test_raw.py | 2 |
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 |