diff --git a/mypy/stubtest.py b/mypy/stubtest.py index f9e6f7d337be..8ea9d786be22 100644 --- a/mypy/stubtest.py +++ b/mypy/stubtest.py @@ -2062,7 +2062,7 @@ def warning_callback(msg: str) -> None: if args.generate_allowlist: generated_allowlist.add(error.object_desc) continue - print(error.get_description(concise=args.concise)) + safe_print(error.get_description(concise=args.concise)) error_count += 1 # Print unused allowlist entries @@ -2102,6 +2102,19 @@ def warning_callback(msg: str) -> None: return exit_code +def safe_print(text: str) -> None: + """Print a text replacing chars not representable in stdout encoding.""" + # If `sys.stdout` encoding is not the same as out (usually UTF8) string, + # if may cause painful crashes. I don't want to reconfigure `sys.stdout` + # to do `errors = "replace"` as that sounds scary. + out_encoding = sys.stdout.encoding + if out_encoding is not None: + # Can be None if stdout is replaced (including our own tests). This should be + # safe to omit if the actual stream doesn't care about encoding. + text = text.encode(out_encoding, errors="replace").decode(out_encoding, errors="replace") + print(text) + + def parse_options(args: list[str]) -> _Arguments: parser = argparse.ArgumentParser( description="Compares stubs to objects introspected from the runtime."