diff -r be27ed110b50 -r d8ac696cc51f buildframework/helium/external/python/lib/common/docutils-0.5-py2.5.egg/docutils/io.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/buildframework/helium/external/python/lib/common/docutils-0.5-py2.5.egg/docutils/io.py Wed Dec 23 19:29:07 2009 +0200 @@ -0,0 +1,412 @@ +# $Id: io.py 4750 2006-09-16 21:32:29Z wiemann $ +# Author: David Goodger +# Copyright: This module has been placed in the public domain. + +""" +I/O classes provide a uniform API for low-level input and output. Subclasses +will exist for a variety of input/output mechanisms. +""" + +__docformat__ = 'reStructuredText' + +import sys +try: + import locale +except: + pass +import re +from types import UnicodeType +from docutils import TransformSpec + + +class Input(TransformSpec): + + """ + Abstract base class for input wrappers. + """ + + component_type = 'input' + + default_source_path = None + + def __init__(self, source=None, source_path=None, encoding=None, + error_handler='strict'): + self.encoding = encoding + """Text encoding for the input source.""" + + self.error_handler = error_handler + """Text decoding error handler.""" + + self.source = source + """The source of input data.""" + + self.source_path = source_path + """A text reference to the source.""" + + if not source_path: + self.source_path = self.default_source_path + + self.successful_encoding = None + """The encoding that successfully decoded the source data.""" + + def __repr__(self): + return '%s: source=%r, source_path=%r' % (self.__class__, self.source, + self.source_path) + + def read(self): + raise NotImplementedError + + def decode(self, data): + """ + Decode a string, `data`, heuristically. + Raise UnicodeError if unsuccessful. + + The client application should call ``locale.setlocale`` at the + beginning of processing:: + + locale.setlocale(locale.LC_ALL, '') + """ + if self.encoding and self.encoding.lower() == 'unicode': + assert isinstance(data, UnicodeType), ( + 'input encoding is "unicode" ' + 'but input is not a unicode object') + if isinstance(data, UnicodeType): + # Accept unicode even if self.encoding != 'unicode'. + return data + if self.encoding: + # We believe the user/application when the encoding is + # explicitly given. + encodings = [self.encoding] + else: + data_encoding = self.determine_encoding_from_data(data) + if data_encoding: + # If the data declares its encoding (explicitly or via a BOM), + # we believe it. + encodings = [data_encoding] + else: + # Apply heuristics only if no encoding is explicitly given and + # no BOM found. Start with UTF-8, because that only matches + # data that *IS* UTF-8: + encodings = ['utf-8'] + try: + # for Python 2.2 compatibility + encodings.append(locale.nl_langinfo(locale.CODESET)) + except: + pass + try: + encodings.append(locale.getlocale()[1]) + except: + pass + try: + encodings.append(locale.getdefaultlocale()[1]) + except: + pass + # fallback encoding: + encodings.append('latin-1') + error = None + error_details = '' + for enc in encodings: + if not enc: + continue + try: + decoded = unicode(data, enc, self.error_handler) + self.successful_encoding = enc + # Return decoded, removing BOMs. + return decoded.replace(u'\ufeff', u'') + except (UnicodeError, LookupError), error: + pass + if error is not None: + error_details = '\n(%s: %s)' % (error.__class__.__name__, error) + raise UnicodeError( + 'Unable to decode input data. Tried the following encodings: ' + '%s.%s' + % (', '.join([repr(enc) for enc in encodings if enc]), + error_details)) + + coding_slug = re.compile("coding[:=]\s*([-\w.]+)") + """Encoding declaration pattern.""" + + byte_order_marks = (('\xef\xbb\xbf', 'utf-8'), + ('\xfe\xff', 'utf-16-be'), + ('\xff\xfe', 'utf-16-le'),) + """Sequence of (start_bytes, encoding) tuples to for encoding detection. + The first bytes of input data are checked against the start_bytes strings. + A match indicates the given encoding.""" + + def determine_encoding_from_data(self, data): + """ + Try to determine the encoding of `data` by looking *in* `data`. + Check for a byte order mark (BOM) or an encoding declaration. + """ + # check for a byte order mark: + for start_bytes, encoding in self.byte_order_marks: + if data.startswith(start_bytes): + return encoding + # check for an encoding declaration pattern in first 2 lines of file: + for line in data.splitlines()[:2]: + match = self.coding_slug.search(line) + if match: + return match.group(1) + return None + + +class Output(TransformSpec): + + """ + Abstract base class for output wrappers. + """ + + component_type = 'output' + + default_destination_path = None + + def __init__(self, destination=None, destination_path=None, + encoding=None, error_handler='strict'): + self.encoding = encoding + """Text encoding for the output destination.""" + + self.error_handler = error_handler or 'strict' + """Text encoding error handler.""" + + self.destination = destination + """The destination for output data.""" + + self.destination_path = destination_path + """A text reference to the destination.""" + + if not destination_path: + self.destination_path = self.default_destination_path + + def __repr__(self): + return ('%s: destination=%r, destination_path=%r' + % (self.__class__, self.destination, self.destination_path)) + + def write(self, data): + """`data` is a Unicode string, to be encoded by `self.encode`.""" + raise NotImplementedError + + def encode(self, data): + if self.encoding and self.encoding.lower() == 'unicode': + assert isinstance(data, UnicodeType), ( + 'the encoding given is "unicode" but the output is not ' + 'a Unicode string') + return data + if not isinstance(data, UnicodeType): + # Non-unicode (e.g. binary) output. + return data + else: + try: + return data.encode(self.encoding, self.error_handler) + except (LookupError, ValueError): + # LookupError is raised if there are unencodable chars + # in data and the error_handler isn't found. In old + # Python versions, ValueError is raised. + if self.error_handler == 'xmlcharrefreplace': + # We are using xmlcharrefreplace with a Python + # version that doesn't support it (2.1, 2.2, or + # IronPython 1.0) so we emulate its behavior. + return ''.join([self.xmlcharref_encode(char) + for char in data]) + else: + raise + + def xmlcharref_encode(self, char): + """Emulate Python 2.3's 'xmlcharrefreplace' encoding error handler.""" + try: + return char.encode(self.encoding, 'strict') + except UnicodeError: + return '&#%i;' % ord(char) + + +class FileInput(Input): + + """ + Input for single, simple file-like objects. + """ + + def __init__(self, source=None, source_path=None, + encoding=None, error_handler='strict', + autoclose=1, handle_io_errors=1): + """ + :Parameters: + - `source`: either a file-like object (which is read directly), or + `None` (which implies `sys.stdin` if no `source_path` given). + - `source_path`: a path to a file, which is opened and then read. + - `encoding`: the expected text encoding of the input file. + - `error_handler`: the encoding error handler to use. + - `autoclose`: close automatically after read (boolean); always + false if `sys.stdin` is the source. + - `handle_io_errors`: summarize I/O errors here, and exit? + """ + Input.__init__(self, source, source_path, encoding, error_handler) + self.autoclose = autoclose + self.handle_io_errors = handle_io_errors + if source is None: + if source_path: + try: + self.source = open(source_path) + except IOError, error: + if not handle_io_errors: + raise + print >>sys.stderr, '%s: %s' % (error.__class__.__name__, + error) + print >>sys.stderr, ( + 'Unable to open source file for reading (%r). Exiting.' + % source_path) + sys.exit(1) + else: + self.source = sys.stdin + self.autoclose = None + if not source_path: + try: + self.source_path = self.source.name + except AttributeError: + pass + + def read(self): + """ + Read and decode a single file and return the data (Unicode string). + """ + try: + data = self.source.read() + finally: + if self.autoclose: + self.close() + return self.decode(data) + + def close(self): + self.source.close() + + +class FileOutput(Output): + + """ + Output for single, simple file-like objects. + """ + + def __init__(self, destination=None, destination_path=None, + encoding=None, error_handler='strict', autoclose=1, + handle_io_errors=1): + """ + :Parameters: + - `destination`: either a file-like object (which is written + directly) or `None` (which implies `sys.stdout` if no + `destination_path` given). + - `destination_path`: a path to a file, which is opened and then + written. + - `autoclose`: close automatically after write (boolean); always + false if `sys.stdout` is the destination. + """ + Output.__init__(self, destination, destination_path, + encoding, error_handler) + self.opened = 1 + self.autoclose = autoclose + self.handle_io_errors = handle_io_errors + if destination is None: + if destination_path: + self.opened = None + else: + self.destination = sys.stdout + self.autoclose = None + if not destination_path: + try: + self.destination_path = self.destination.name + except AttributeError: + pass + + def open(self): + try: + self.destination = open(self.destination_path, 'w') + except IOError, error: + if not self.handle_io_errors: + raise + print >>sys.stderr, '%s: %s' % (error.__class__.__name__, + error) + print >>sys.stderr, ('Unable to open destination file for writing ' + '(%r). Exiting.' % self.destination_path) + sys.exit(1) + self.opened = 1 + + def write(self, data): + """Encode `data`, write it to a single file, and return it.""" + output = self.encode(data) + if not self.opened: + self.open() + try: + self.destination.write(output) + finally: + if self.autoclose: + self.close() + return output + + def close(self): + self.destination.close() + self.opened = None + + +class StringInput(Input): + + """ + Direct string input. + """ + + default_source_path = '' + + def read(self): + """Decode and return the source string.""" + return self.decode(self.source) + + +class StringOutput(Output): + + """ + Direct string output. + """ + + default_destination_path = '' + + def write(self, data): + """Encode `data`, store it in `self.destination`, and return it.""" + self.destination = self.encode(data) + return self.destination + + +class NullInput(Input): + + """ + Degenerate input: read nothing. + """ + + default_source_path = 'null input' + + def read(self): + """Return a null string.""" + return u'' + + +class NullOutput(Output): + + """ + Degenerate output: write nothing. + """ + + default_destination_path = 'null output' + + def write(self, data): + """Do nothing ([don't even] send data to the bit bucket).""" + pass + + +class DocTreeInput(Input): + + """ + Adapter for document tree input. + + The document tree must be passed in the ``source`` parameter. + """ + + default_source_path = 'doctree input' + + def read(self): + """Return the document tree.""" + return self.source