def __init__( self, filelike: io.IOBase, mode: str = None, encoding: str = None, non_blocking: bool = False, ) -> None: if not isinstance(filelike, io.IOBase): raise TypeError("must be a file-like object") filelike = self._maybe_text(filelike) filelike = self._maybe_bytes(filelike) self._maybe_raw(filelike) self._maybe_fd(filelike) try: self.isatty = filelike.isatty() except AttributeError: self.isatty = os.isatty(self.fd) if self.fd is not None else False self.encoding = None self._determine_encoding(encoding) if non_blocking and self.fd is not None and os.get_blocking(self.fd): os.set_blocking(self.fd, False) mode, accmode = self._determine_mode(mode) mode, accmode = self._maybe_raw_from_fd(mode, accmode) mode, accmode = self._maybe_bytes_from_raw(mode, accmode) self._maybe_text_from_bytes(mode, accmode)
def test_attributes_iobase(sio: io.IOBase) -> None: """Check basic attrs/descriptor functions related to being subclass of io.IOBase.""" assert sio is not None assert isinstance(sio, io.IOBase) assert isinstance(sio, io.RawIOBase) assert not isinstance(sio, io.TextIOBase) assert sio.readable() is True assert sio.writable() is True assert sio.seekable() is False assert sio.isatty() is False assert sio.closed() is False
def pprint_positional_error(error: span_mod.PositionalError, *, output: io.IOBase = sys.stderr, color: Optional[bool] = None, error_context_line_count: int = 5, fs_open: Optional[Callable] = None) -> None: """Prints pretty message to output for a error with a position. ANSI color escapes are used when output appears to be a tty. Args: error: The parse error that was raised in our attempt to parse. output: File to which we'll print the pretty error text. color: If provided, forces color on (True) or forces color off (False). Otherwise attempts to detect whether the output environment supports color. error_context_line_count: Number of context lines to print around the error position. fs_open: If not None, will be used in lieu of builtins.open; useful for e.g. faking out filesystems in test environments. Raises: ValueError: if the error_context_line_count is not odd (only odd values can be symmetrical around the erroneous line). """ assert isinstance(error, span_mod.PositionalError), error if error.printed: return error.printed = True if error_context_line_count % 2 != 1: raise ValueError( 'Expected odd error_context_line_count; got {}'.format( error_context_line_count)) span = error.span # If nobody is hooking "open", use the built-in one. fs_open = fs_open or builtins.open with fs_open(error.filename) as f: text = f.read() lines = text.splitlines() if span.limit.lineno >= len(lines): raise ValueError( 'Position of error is outside of the range of text lines; ' 'error lineno: {}; lines: {}; message was: {}'.format( span.limit.lineno, len(lines), error.message)) line_count_each_side = error_context_line_count // 2 low_lineno = max(span.start.lineno - line_count_each_side, 0) lines_before = lines[low_lineno:span.start.lineno] target_line = lines[span.start.lineno] # Note: since this is a limit there's a trailing +1. high_lineno = span.limit.lineno + line_count_each_side + 1 lines_after = lines[span.start.lineno + 1:high_lineno] # Note: "color" is a tristate, None means no fixed request. use_color = color is True # pylint: disable=g-bool-id-comparison use_color = use_color or (color is None and output.isatty()) if use_color: fmt = termcolor.colored('{} {:04d}:', color='yellow') + ' {}' print_red = functools.partial(termcolor.cprint, color='red', file=output) else: fmt = '{} {:04d}: {}' print_red = functools.partial(print, file=output) def emit_line(lineno: int, line: Text, is_culprit: bool = False): # Note: humans generally think line i=0 is "line 1". print(fmt.format('*' if is_culprit else ' ', lineno + 1, line), file=output) leader = f'{error.filename}:{low_lineno+1}-{high_lineno}' print(termcolor.colored(leader, 'yellow') if use_color else leader, file=output) for i, line in enumerate(lines_before): emit_line(low_lineno + i, line) # Emit the culprit line. emit_line(span.start.lineno, target_line, is_culprit=True) # Emit error indicator, leading spaces correspond to leading line number. print_red('{:8s}'.format('') + '~' * span.start.colno + '^' + '-' * (max(0, span.limit.colno - span.start.colno - 2)) + '^ ' + str(error)) # Emit the lines that come after. for i, line in enumerate(lines_after): emit_line(span.start.lineno + 1 + i, line)