def has_next(peekable: more_itertools.peekable) -> bool: """Return True if the peekable has a next element.""" try: peekable.peek() return True except StopIteration: return False
def _parse_string(json_iterator: peekable) -> str: result = '' json_iterator.next() # Skip over opening " while True: next_char = json_iterator.next() if next_char == '"' and not result.endswith('\\'): break result += next_char return result
def _parse_null(json_iterator: peekable): value = '' while json_iterator.peek() not in string.whitespace and json_iterator.peek( ) not in (_token_separator, _object_end, _array_end): value += json_iterator.next() if value == 'null': return None else: raise ParseError('Invalid string "' + value + '" found while trying to parse a null value')
def _parse_boolean(json_iterator: peekable) -> bool: value = '' while json_iterator.peek() not in string.whitespace and json_iterator.peek( ) not in (_token_separator, _object_end, _array_end): value += json_iterator.next() if value == 'true': return True elif value == 'false': return False else: raise ParseError('Invalid string "' + value + '" found while trying to parse a boolean value')
def _take_until(iterable: more_itertools.peekable, predicate): try: yield next(iterable) while not predicate(iterable.peek()): yield next(iterable) except StopIteration: return
def _read_query(cls, lines: peekable): qls = [] line = lines.peek(None) while line is not None and not cls._sep_re.match(line): qls.append(next(lines)) line = lines.peek(None) # trim lines while qls and not qls[0].strip(): qls.pop(0) while qls and not qls[-1].strip(): qls.pop(-1) if qls or line is not None: return qls else: return None # end of file
def _parse_array(json_iterator: peekable) -> list: values = [] json_iterator.next() # Skip over opening [ _whitespace_skip(json_iterator) next_char = json_iterator.peek() if next_char == _array_end: json_iterator.next() return [] # Empty Array while True: if next_char == _object_start: element_value = _parse_object(json_iterator) elif next_char == _array_start: element_value = _parse_array(json_iterator) elif next_char == _string_delimiter: element_value = _parse_string(json_iterator) elif next_char in _numeric_start: element_value = _parse_numeric(json_iterator) elif next_char in _boolean_start: # JSON defines boolean values as "true" or "false" exclusively element_value = _parse_boolean(json_iterator) elif next_char == _null_start: # JSON defines a "null" value element_value = _parse_null(json_iterator) values.append(element_value) _whitespace_skip(json_iterator) next_char = json_iterator.peek() if next_char == _array_end: json_iterator.next() return values elif next_char == _token_separator: next_char = json_iterator.next() _whitespace_skip(json_iterator) next_char = json_iterator.peek() else: raise ParseError( 'Unexpected character while trying to parse array: "' + next_char + '"')
def _parse_numeric(json_iterator: peekable) -> numbers.Number: value = '' next_char = json_iterator.next() while True: value += next_char next_char = json_iterator.peek() if next_char in string.whitespace or next_char in (_token_separator, _object_end, _array_end): break else: next_char = json_iterator.next() try: return int(value) except ValueError: try: return float(value) except ValueError: raise ParseError('String ' + value + ' could not be parsed as a number')
def _read_header(cls, lines: peekable): label = None errs = [] tx = True line = lines.peek(None) while line is not None: hm = cls._sep_re.match(line) if hm is None: break next(lines) # eat line line = lines.peek(None) inst = hm.group('inst') cm = cls._icode_re.match(inst) if cm is None: continue code = cm.group('code') args = cm.group('args') if code == 'step': label = args elif code == 'allow': err = getattr(psycopg2.errorcodes, args.upper()) _log.debug('step allows error %s (%s)', args, err) errs.append(err) elif code == 'notx': _log.debug('chunk will run outside a transaction') tx = False else: _log.error('unrecognized query instruction %s', code) raise ValueError(f'invalid query instruction {code}') return ScriptChunk(label=label, allowed_errors=errs, src=None, use_transaction=tx)
def _whitespace_skip(json_iterator: peekable): while json_iterator.peek() in string.whitespace: json_iterator.next()
def _parse_object(json_iterator: peekable) -> dict: next_char = json_iterator.next() if next_char != _object_start: raise ParseError( 'Unexpected character while trying to parse object: "' + next_char + '"') # Skip over whitespace _whitespace_skip(json_iterator) next_char = json_iterator.peek() if next_char == _object_end: json_iterator.next() return {} tokens = {} while True: # At the object level, a valid element follows the form "<element name AS string> : <value>" if json_iterator.peek() not in (_string_delimiter, _token_separator): raise ParseError('Unexpected character: "' + next_char + '"') element_name = _parse_string(json_iterator) element_value = None # Advance to the separator and the start of the value _whitespace_skip(json_iterator) next_char = json_iterator.peek() if next_char != _pair_separator: raise ParseError('Unexpected character while parsing element ' + element_name + ': "' + next_char + '"') json_iterator.next() _whitespace_skip(json_iterator) # Parse the value element next_char = json_iterator.peek() if next_char == _object_start: element_value = _parse_object(json_iterator) elif next_char == _array_start: element_value = _parse_array(json_iterator) elif next_char == _string_delimiter: element_value = _parse_string(json_iterator) elif next_char in _numeric_start: element_value = _parse_numeric(json_iterator) elif next_char in _boolean_start: # JSON defines boolean values as "true" or "false" exclusively element_value = _parse_boolean(json_iterator) elif next_char == _null_start: # JSON defines a "null" value element_value = _parse_null(json_iterator) else: # We've hit something invalid, let's abort raise ParseError('Unexpected character while parsing element ' + element_name + ': "' + next_char + '"') tokens[element_name] = element_value # Advance the iterator over whitespace, the token separator, whitespace to the start of the next token _whitespace_skip(json_iterator) next_char = json_iterator.peek() if not next_char in (_pair_separator, _object_end, _token_separator): raise ParseError('Unexpected character while parsing element ' + element_name + ': "' + next_char + '"') json_iterator.next() if next_char == _object_end: break _whitespace_skip(json_iterator) return tokens