CoolFace
Apppublic

Aluode/PerceptionLabPortable

sourceHugging Faceupdated 9mo agoView on Hugging Face
0likes
reader.py186 linesDownload Raw Back to yaml
1# This module contains abstractions for the input stream. You don't have to2# looks further, there are no pretty code.3#4# We define two classes here.5#6#   Mark(source, line, column)7# It's just a record and its only use is producing nice error messages.8# Parser does not use it for any other purposes.9#10#   Reader(source, data)11# Reader determines the encoding of `data` and converts it to unicode.12# Reader provides the following methods and attributes:13#   reader.peek(length=1) - return the next `length` characters14#   reader.forward(length=1) - move the current position to `length` characters.15#   reader.index - the number of the current character.16#   reader.line, stream.column - the line and the column of the current character.17 18__all__ = ['Reader', 'ReaderError']19 20from .error import YAMLError, Mark21 22import codecs, re23 24class ReaderError(YAMLError):25 26    def __init__(self, name, position, character, encoding, reason):27        self.name = name28        self.character = character29        self.position = position30        self.encoding = encoding31        self.reason = reason32 33    def __str__(self):34        if isinstance(self.character, bytes):35            return "'%s' codec can't decode byte #x%02x: %s\n"  \36                    "  in \"%s\", position %d"    \37                    % (self.encoding, ord(self.character), self.reason,38                            self.name, self.position)39        else:40            return "unacceptable character #x%04x: %s\n"    \41                    "  in \"%s\", position %d"    \42                    % (self.character, self.reason,43                            self.name, self.position)44 45class Reader(object):46    # Reader:47    # - determines the data encoding and converts it to a unicode string,48    # - checks if characters are in allowed range,49    # - adds '\0' to the end.50 51    # Reader accepts52    #  - a `bytes` object,53    #  - a `str` object,54    #  - a file-like object with its `read` method returning `str`,55    #  - a file-like object with its `read` method returning `unicode`.56 57    # Yeah, it's ugly and slow.58 59    def __init__(self, stream):60        self.name = None61        self.stream = None62        self.stream_pointer = 063        self.eof = True64        self.buffer = ''65        self.pointer = 066        self.raw_buffer = None67        self.raw_decode = None68        self.encoding = None69        self.index = 070        self.line = 071        self.column = 072        if isinstance(stream, str):73            self.name = "<unicode string>"74            self.check_printable(stream)75            self.buffer = stream+'\0'76        elif isinstance(stream, bytes):77            self.name = "<byte string>"78            self.raw_buffer = stream79            self.determine_encoding()80        else:81            self.stream = stream82            self.name = getattr(stream, 'name', "<file>")83            self.eof = False84            self.raw_buffer = None85            self.determine_encoding()86 87    def peek(self, index=0):88        try:89            return self.buffer[self.pointer+index]90        except IndexError:91            self.update(index+1)92            return self.buffer[self.pointer+index]93 94    def prefix(self, length=1):95        if self.pointer+length >= len(self.buffer):96            self.update(length)97        return self.buffer[self.pointer:self.pointer+length]98 99    def forward(self, length=1):100        if self.pointer+length+1 >= len(self.buffer):101            self.update(length+1)102        while length:103            ch = self.buffer[self.pointer]104            self.pointer += 1105            self.index += 1106            if ch in '\n\x85\u2028\u2029'  \107                    or (ch == '\r' and self.buffer[self.pointer] != '\n'):108                self.line += 1109                self.column = 0110            elif ch != '\uFEFF':111                self.column += 1112            length -= 1113 114    def get_mark(self):115        if self.stream is None:116            return Mark(self.name, self.index, self.line, self.column,117                    self.buffer, self.pointer)118        else:119            return Mark(self.name, self.index, self.line, self.column,120                    None, None)121 122    def determine_encoding(self):123        while not self.eof and (self.raw_buffer is None or len(self.raw_buffer) < 2):124            self.update_raw()125        if isinstance(self.raw_buffer, bytes):126            if self.raw_buffer.startswith(codecs.BOM_UTF16_LE):127                self.raw_decode = codecs.utf_16_le_decode128                self.encoding = 'utf-16-le'129            elif self.raw_buffer.startswith(codecs.BOM_UTF16_BE):130                self.raw_decode = codecs.utf_16_be_decode131                self.encoding = 'utf-16-be'132            else:133                self.raw_decode = codecs.utf_8_decode134                self.encoding = 'utf-8'135        self.update(1)136 137    NON_PRINTABLE = re.compile('[^\x09\x0A\x0D\x20-\x7E\x85\xA0-\uD7FF\uE000-\uFFFD\U00010000-\U0010ffff]')138    def check_printable(self, data):139        match = self.NON_PRINTABLE.search(data)140        if match:141            character = match.group()142            position = self.index+(len(self.buffer)-self.pointer)+match.start()143            raise ReaderError(self.name, position, ord(character),144                    'unicode', "special characters are not allowed")145 146    def update(self, length):147        if self.raw_buffer is None:148            return149        self.buffer = self.buffer[self.pointer:]150        self.pointer = 0151        while len(self.buffer) < length:152            if not self.eof:153                self.update_raw()154            if self.raw_decode is not None:155                try:156                    data, converted = self.raw_decode(self.raw_buffer,157                            'strict', self.eof)158                except UnicodeDecodeError as exc:159                    character = self.raw_buffer[exc.start]160                    if self.stream is not None:161                        position = self.stream_pointer-len(self.raw_buffer)+exc.start162                    else:163                        position = exc.start164                    raise ReaderError(self.name, position, character,165                            exc.encoding, exc.reason)166            else:167                data = self.raw_buffer168                converted = len(data)169            self.check_printable(data)170            self.buffer += data171            self.raw_buffer = self.raw_buffer[converted:]172            if self.eof:173                self.buffer += '\0'174                self.raw_buffer = None175                break176 177    def update_raw(self, size=4096):178        data = self.stream.read(size)179        if self.raw_buffer is None:180            self.raw_buffer = data181        else:182            self.raw_buffer += data183        self.stream_pointer += len(data)184        if not data:185            self.eof = True186 
Aluode/PerceptionLabPortable · CoolFace