def __init__(self, *args: str, redirect: bool = True, **kwargs: Any) -> None: """ enrich console does soft-wrapping by default and this diverge from original rich console which does not, creating hard-wraps instead. """ self.redirect = redirect if "soft_wrap" not in kwargs: kwargs["soft_wrap"] = True # Unless user already mentioning terminal preference, we use our # heuristic to make an informed decision. if "force_terminal" not in kwargs: kwargs["force_terminal"] = should_do_markup( stream=kwargs.get("file", sys.stdout)) super().__init__(*args, **kwargs) self.extended = True if self.redirect: if not hasattr(sys.stdout, "rich_proxied_file"): sys.stdout = FileProxy(self, sys.stdout) # type: ignore if not hasattr(sys.stderr, "rich_proxied_file"): sys.stderr = FileProxy(self, sys.stderr) # type: ignore
def telnet(): from pdbr.__main__ import RichPdb pdb_cls = RichPdb() if len(sys.argv) < 3: pdb_cls.error("Usage : pdbr_telnet hostname port") sys.exit() class MyTelnet(Telnet): def fill_rawq(self): """ exactly the same with Telnet.fill_rawq, buffer size is just changed from 50 to 1024. """ if self.irawq >= len(self.rawq): self.rawq = b"" self.irawq = 0 buf = self.sock.recv(1024) self.msg("recv %r", buf) self.eof = not buf self.rawq = self.rawq + buf console = pdb_cls.console sys.stdout = FileProxy(console, sys.stdout) sys.stderr = FileProxy(console, sys.stderr) try: host = sys.argv[1] port = int(sys.argv[2]) with MyTelnet(host, port) as tn: tn.interact() except BaseException as e: pdb_cls.error(e) sys.exit()
def test_empty_bytes(): console = Console() file_proxy = FileProxy(console, sys.stdout) # File should raise TypeError when writing bytes with pytest.raises(TypeError): file_proxy.write(b"") # type: ignore with pytest.raises(TypeError): file_proxy.write(b"foo") # type: ignore
def test_flush(): file = io.StringIO() console = Console(file=file) file_proxy = FileProxy(console, file) file_proxy.write("foo") assert file.getvalue() == "" file_proxy.flush() assert file.getvalue() == "foo\n"
def test_new_lines(): file = io.StringIO() console = Console(file=file) file_proxy = FileProxy(console, file) file_proxy.write("-\n-") assert file.getvalue() == "-\n" file_proxy.flush() assert file.getvalue() == "-\n-\n"
def _run( self, input_path: pathlib.Path, width: int, height: int, total_frames: int, frame_rate: float, output_path: pathlib.Path, output_width: int, output_height: int, Processor: object, mode: str, processes: int, processing_settings: tuple, ) -> None: # record original STDOUT and STDERR for restoration original_stdout = sys.stdout original_stderr = sys.stderr # create console for rich's Live display console = Console() # redirect STDOUT and STDERR to console sys.stdout = FileProxy(console, sys.stdout) sys.stderr = FileProxy(console, sys.stderr) # re-add Loguru to point to the new STDERR logger.remove() logger.add(sys.stderr, colorize=True, format=LOGURU_FORMAT) # initialize values self.processor_processes = [] self.processing_queue = multiprocessing.Queue(maxsize=processes * 10) processed_frames = multiprocessing.Manager().list([None] * total_frames) self.processed = multiprocessing.Value("I", 0) self.pause = multiprocessing.Value(ctypes.c_bool, False) # set up and start decoder thread logger.info("Starting video decoder") self.decoder = VideoDecoder( input_path, width, height, frame_rate, self.processing_queue, processing_settings, self.pause, ) self.decoder.start() # set up and start encoder thread logger.info("Starting video encoder") self.encoder = VideoEncoder( input_path, frame_rate * 2 if mode == "interpolate" else frame_rate, output_path, output_width, output_height, total_frames, processed_frames, self.processed, self.pause, ) self.encoder.start() # create processor processes for process_name in range(processes): process = Processor(self.processing_queue, processed_frames, self.pause) process.name = str(process_name) process.daemon = True process.start() self.processor_processes.append(process) # create progress bar self.progress = Progress( "[progress.description]{task.description}", BarColumn(complete_style="blue", finished_style="green"), "[progress.percentage]{task.percentage:>3.0f}%", "[color(240)]({task.completed}/{task.total})", ProcessingSpeedColumn(), TimeElapsedColumn(), "<", TimeRemainingColumn(), console=console, speed_estimate_period=300.0, disable=True, ) self.description = f"[cyan]{MODE_LABELS.get(mode, 'Unknown')}" self.task = self.progress.add_task(self.description, total=total_frames) # allow sending SIGUSR1 to pause/resume processing signal.signal(signal.SIGUSR1, self._toggle_pause) # enable global pause hotkey if it's supported if ENABLE_HOTKEY is True: # create global pause hotkey pause_hotkey = pynput.keyboard.HotKey( pynput.keyboard.HotKey.parse("<ctrl>+<alt>+v"), self._toggle_pause ) # create global keyboard input listener keyboard_listener = pynput.keyboard.Listener( on_press=( lambda key: pause_hotkey.press(keyboard_listener.canonical(key)) ), on_release=( lambda key: pause_hotkey.release(keyboard_listener.canonical(key)) ), ) # start monitoring global key presses keyboard_listener.start() # a temporary variable that stores the exception exception = [] try: # wait for jobs in queue to deplete while self.processed.value < total_frames - 1: time.sleep(1) # check processor health for process in self.processor_processes: if not process.is_alive(): raise Exception("process died unexpectedly") # check decoder health if not self.decoder.is_alive() and self.decoder.exception is not None: raise Exception("decoder died unexpectedly") # check encoder health if not self.encoder.is_alive() and self.encoder.exception is not None: raise Exception("encoder died unexpectedly") # show progress bar when upscale starts if self.progress.disable is True and self.processed.value > 0: self.progress.disable = False self.progress.start() # update progress if self.pause.value is False: self.progress.update(self.task, completed=self.processed.value) self.progress.update(self.task, completed=total_frames) self.progress.stop() logger.info("Processing has completed") # if SIGTERM is received or ^C is pressed # TODO: pause and continue here except (SystemExit, KeyboardInterrupt) as e: self.progress.stop() logger.warning("Exit signal received, exiting gracefully") logger.warning("Press ^C again to force terminate") exception.append(e) except Exception as e: self.progress.stop() logger.exception(e) exception.append(e) finally: # stop keyboard listener if ENABLE_HOTKEY is True: keyboard_listener.stop() keyboard_listener.join() # stop progress display self.progress.stop() # stop processor processes logger.info("Stopping processor processes") for process in self.processor_processes: process.terminate() # wait for processes to finish for process in self.processor_processes: process.join() # stop encoder and decoder logger.info("Stopping decoder and encoder threads") self.decoder.stop() self.encoder.stop() self.decoder.join() self.encoder.join() # mark processing queue as closed self.processing_queue.close() # raise the error if there is any if len(exception) > 0: raise exception[0] # restore original STDOUT and STDERR sys.stdout = original_stdout sys.stderr = original_stderr # re-add Loguru to point to the restored STDERR logger.remove() logger.add(sys.stderr, colorize=True, format=LOGURU_FORMAT)